loading
Generated 2021-03-08T10:24:45+03:00

All Files ( 40.4% covered at 0.72 hits/line )

256 files in total.
8758 relevant lines, 3538 lines covered and 5220 lines missed. ( 40.4% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
app/admin/builders.rb 10.53 % 30 19 2 17 0.11
app/admin/dashboard.rb 20.00 % 30 15 3 12 0.20
app/admin/event_logs.rb 25.00 % 37 24 6 18 0.25
app/admin/flash_notifies.rb 27.78 % 29 18 5 13 0.28
app/admin/resque.rb 100.00 % 3 2 2 0 1.00
app/admin/users.rb 35.71 % 66 42 15 27 0.36
app/controllers/advisories_controller.rb 28.57 % 34 21 6 15 0.29
app/controllers/api/v1/advisories_controller.rb 46.43 % 52 28 13 15 0.46
app/controllers/api/v1/arches_controller.rb 60.00 % 9 5 3 2 0.60
app/controllers/api/v1/base_controller.rb 30.43 % 127 69 21 48 0.30
app/controllers/api/v1/build_lists_controller.rb 33.33 % 96 51 17 34 0.33
app/controllers/api/v1/groups_controller.rb 45.95 % 67 37 17 20 0.46
app/controllers/api/v1/issues_controller.rb 25.37 % 112 67 17 50 0.25
app/controllers/api/v1/jobs_controller.rb 19.72 % 130 71 14 57 0.20
app/controllers/api/v1/maintainers_controller.rb 60.00 % 11 5 3 2 0.60
app/controllers/api/v1/platforms_controller.rb 37.50 % 96 56 21 35 0.38
app/controllers/api/v1/product_build_lists_controller.rb 42.42 % 59 33 14 19 0.42
app/controllers/api/v1/products_controller.rb 71.43 % 29 14 10 4 0.71
app/controllers/api/v1/projects_controller.rb 41.30 % 85 46 19 27 0.41
app/controllers/api/v1/pull_requests_controller.rb 20.18 % 172 109 22 87 0.20
app/controllers/api/v1/repositories_controller.rb 31.34 % 125 67 21 46 0.31
app/controllers/api/v1/search_controller.rb 25.00 % 12 8 2 6 0.25
app/controllers/api/v1/users_controller.rb 41.18 % 63 34 14 20 0.41
app/controllers/application_controller.rb 63.41 % 165 82 52 30 1.11
app/controllers/autocompletes_controller.rb 37.93 % 68 29 11 18 0.38
app/controllers/concerns/api/v1/issueable.rb 55.56 % 45 18 10 8 0.56
app/controllers/concerns/strong_params.rb 62.50 % 16 8 5 3 0.63
app/controllers/groups/base_controller.rb 71.43 % 13 7 5 2 0.71
app/controllers/groups/members_controller.rb 25.00 % 38 24 6 18 0.25
app/controllers/groups/profile_controller.rb 25.42 % 93 59 15 44 0.25
app/controllers/home_controller.rb 16.67 % 112 60 10 50 0.17
app/controllers/pages_controller.rb 50.00 % 22 10 5 5 0.50
app/controllers/platforms/base_controller.rb 66.67 % 11 6 4 2 0.67
app/controllers/platforms/contents_controller.rb 35.29 % 28 17 6 11 0.35
app/controllers/platforms/key_pairs_controller.rb 26.32 % 31 19 5 14 0.26
app/controllers/platforms/maintainers_controller.rb 50.00 % 16 10 5 5 0.50
app/controllers/platforms/mass_builds_controller.rb 19.74 % 126 76 15 61 0.20
app/controllers/platforms/platforms_controller.rb 20.91 % 176 110 23 87 0.21
app/controllers/platforms/product_build_lists_controller.rb 28.57 % 123 70 20 50 0.29
app/controllers/platforms/products_controller.rb 40.00 % 73 40 16 24 0.40
app/controllers/platforms/repositories_controller.rb 25.93 % 192 108 28 80 0.26
app/controllers/platforms/tokens_controller.rb 34.38 % 62 32 11 21 0.34
app/controllers/projects/base_controller.rb 76.47 % 26 17 13 4 1.12
app/controllers/projects/build_lists_controller.rb 29.20 % 246 137 40 97 0.35
app/controllers/projects/collaborators_controller.rb 33.33 % 78 45 15 30 0.33
app/controllers/projects/comments_controller.rb 38.24 % 65 34 13 21 0.38
app/controllers/projects/commit_subscribes_controller.rb 41.18 % 28 17 7 10 0.41
app/controllers/projects/git/base_controller.rb 76.92 % 22 13 10 3 0.77
app/controllers/projects/git/blobs_controller.rb 43.48 % 40 23 10 13 0.43
app/controllers/projects/git/commits_controller.rb 12.90 % 50 31 4 27 0.13
app/controllers/projects/git/trees_controller.rb 25.37 % 110 67 17 50 0.25
app/controllers/projects/hooks_controller.rb 40.63 % 56 32 13 19 0.41
app/controllers/projects/issues_controller.rb 22.92 % 176 96 22 74 0.23
app/controllers/projects/projects_controller.rb 18.57 % 214 140 26 114 0.19
app/controllers/projects/pull_requests_controller.rb 17.27 % 169 110 19 91 0.17
app/controllers/projects/subscribes_controller.rb 38.89 % 31 18 7 11 0.39
app/controllers/projects/wiki_controller.rb 18.58 % 287 183 34 149 0.19
app/controllers/robots_controller.rb 75.00 % 7 4 3 1 0.75
app/controllers/search_controller.rb 55.56 % 13 9 5 4 0.56
app/controllers/statistics_controller.rb 11.63 % 80 43 5 38 0.12
app/controllers/users/base_controller.rb 66.67 % 16 9 6 3 0.67
app/controllers/users/profile_controller.rb 25.00 % 28 16 4 12 0.25
app/controllers/users/registrations_controller.rb 25.00 % 58 36 9 27 0.25
app/controllers/users/settings_controller.rb 27.12 % 97 59 16 43 0.27
app/controllers/users/ssh_keys_controller.rb 40.91 % 38 22 9 13 0.41
app/controllers/users/users_controller.rb 47.37 % 32 19 9 10 0.47
app/helpers/active_admin/admin_helper.rb 75.00 % 10 4 3 1 0.75
app/helpers/activity_feeds_helper.rb 33.33 % 34 18 6 12 0.33
app/helpers/advisories_helper.rb 33.33 % 21 12 4 8 0.33
app/helpers/application_helper.rb 18.03 % 121 61 11 50 0.18
app/helpers/avatar_helper.rb 40.00 % 8 5 2 3 0.40
app/helpers/build_lists_helper.rb 26.06 % 336 142 37 105 0.26
app/helpers/comments_helper.rb 27.78 % 29 18 5 13 0.28
app/helpers/commit_helper.rb 15.15 % 196 132 20 112 0.15
app/helpers/datatable_helper.rb 57.14 % 14 7 4 3 0.57
app/helpers/devise_helper.rb 30.00 % 20 10 3 7 0.30
app/helpers/diff_helper.rb 25.95 % 332 158 41 117 0.26
app/helpers/file_store_helper.rb 33.33 % 17 9 3 6 0.33
app/helpers/git_helper.rb 11.65 % 161 103 12 91 0.12
app/helpers/gitlab_markdown_helper.rb 25.58 % 102 43 11 32 0.26
app/helpers/hooks_helper.rb 100.00 % 2 1 1 0 1.00
app/helpers/issues_helper.rb 33.33 % 8 6 2 4 0.33
app/helpers/key_pairs_helper.rb 50.00 % 8 4 2 2 0.50
app/helpers/markdown_helper.rb 25.00 % 177 64 16 48 0.25
app/helpers/mass_build_helper.rb 40.00 % 25 10 4 6 0.40
app/helpers/paginate_helper.rb 21.05 % 34 19 4 15 0.21
app/helpers/platforms_helper.rb 28.00 % 46 25 7 18 0.28
app/helpers/product_build_lists_helper.rb 66.67 % 7 3 2 1 0.67
app/helpers/projects_helper.rb 28.30 % 106 53 15 38 0.28
app/helpers/pull_request_helper.rb 22.22 % 61 36 8 28 0.22
app/helpers/repositories_helper.rb 100.00 % 3 1 1 0 1.00
app/helpers/statistics_helper.rb 50.00 % 9 4 2 2 0.50
app/helpers/title_helper.rb 33.33 % 19 12 4 8 0.33
app/helpers/users_helper.rb 33.33 % 21 12 4 8 0.33
app/helpers/wiki_helper.rb 38.18 % 106 55 21 34 0.38
app/jobs/abf_worker/base_observer.rb 55.56 % 42 27 15 12 0.56
app/jobs/abf_worker/iso_worker_observer.rb 35.71 % 31 14 5 9 0.36
app/jobs/abf_worker/publish_observer.rb 14.55 % 93 55 8 47 0.15
app/jobs/abf_worker/rpm_worker_observer.rb 18.03 % 112 61 11 50 0.18
app/jobs/autostart_builds_daily_job.rb 50.00 % 6 4 2 2 0.50
app/jobs/autostart_builds_once_every_twelve_hours_job.rb 50.00 % 6 4 2 2 0.50
app/jobs/autostart_builds_weekly_job.rb 50.00 % 6 4 2 2 0.50
app/jobs/autostart_regens_daily_job.rb 66.67 % 5 3 2 1 0.67
app/jobs/autostart_regens_weekly_job.rb 66.67 % 5 3 2 1 0.67
app/jobs/build_lists/build_canceling_destroy_job.rb 75.00 % 7 4 3 1 0.75
app/jobs/build_lists/clean_buildroot_job.rb 40.00 % 31 15 6 9 0.40
app/jobs/build_lists/create_container_job.rb 57.14 % 12 7 4 3 0.57
app/jobs/build_lists/dependent_packages_job.rb 12.50 % 61 32 4 28 0.13
app/jobs/clean_api_defender_statistics_job.rb 37.50 % 17 8 3 5 0.38
app/jobs/clean_rpm_build_node_job.rb 60.00 % 10 5 3 2 0.60
app/jobs/clean_temp_pull_requests_job.rb 60.00 % 8 5 3 2 0.60
app/jobs/clear_stale_builders_job.rb 75.00 % 9 4 3 1 0.75
app/jobs/clear_unused_invites_job.rb 75.00 % 7 4 3 1 0.75
app/jobs/create_empty_metadata_job.rb 28.21 % 72 39 11 28 0.28
app/jobs/destroy_project_from_repository_job.rb 50.00 % 8 4 2 2 0.50
app/jobs/publish_task_manager_job.rb 38.10 % 42 21 8 13 0.38
app/jobs/remove_outdated_items_job.rb 11.76 % 23 17 2 15 0.12
app/jobs/restart_nodes_job.rb 50.00 % 11 6 3 3 0.50
app/jobs/run_extra_mass_builds_job.rb 42.86 % 30 14 6 8 0.43
app/mailers/user_mailer.rb 32.73 % 121 55 18 37 0.33
app/models/activity_feed.rb 93.33 % 22 15 14 1 4.93
app/models/advisory.rb 47.92 % 74 48 23 25 0.48
app/models/arch.rb 100.00 % 9 5 5 0 1.00
app/models/avatar.rb 100.00 % 18 11 11 0 1.27
app/models/build_list.rb 59.32 % 738 354 210 144 1.08
app/models/build_list/filter.rb 20.00 % 102 50 10 40 0.20
app/models/build_list/item.rb 50.00 % 42 18 9 9 0.50
app/models/build_list/package.rb 56.10 % 84 41 23 18 0.56
app/models/collaborator.rb 39.53 % 154 86 34 52 0.40
app/models/comment.rb 24.41 % 217 127 31 96 0.24
app/models/concerns/abf_worker_methods.rb 44.12 % 77 34 15 19 0.44
app/models/concerns/acts_like_member.rb 75.00 % 37 16 12 4 1.81
app/models/concerns/autostart.rb 85.71 % 29 14 12 2 0.93
app/models/concerns/build_list_observer.rb 65.00 % 45 20 13 7 1.15
app/models/concerns/commit_and_version.rb 78.95 % 33 19 15 4 2.05
app/models/concerns/default_branchable.rb 100.00 % 9 4 4 0 1.50
app/models/concerns/empty_metadata.rb 71.43 % 13 7 5 2 0.86
app/models/concerns/event_loggable.rb 62.50 % 32 16 10 6 4.69
app/models/concerns/external_nodable.rb 100.00 % 12 5 5 0 1.40
app/models/concerns/feed/build_list.rb 70.00 % 44 10 7 3 0.90
app/models/concerns/feed/comment.rb 30.77 % 72 26 8 18 0.31
app/models/concerns/feed/git.rb 5.56 % 82 36 2 34 0.06
app/models/concerns/feed/issue.rb 46.15 % 70 26 12 14 0.46
app/models/concerns/feed/user.rb 100.00 % 17 7 7 0 4.29
app/models/concerns/file_store_clean.rb 56.25 % 29 16 9 7 1.06
app/models/concerns/flash_notify/finders.rb 76.92 % 33 13 10 3 0.77
app/models/concerns/git.rb 31.14 % 298 167 52 115 0.73
app/models/concerns/owner.rb 100.00 % 10 6 6 0 4.67
app/models/concerns/personal_repository.rb 92.00 % 38 25 23 2 7.40
app/models/concerns/platform/finders.rb 91.67 % 50 24 22 2 3.75
app/models/concerns/product_build_lists/abf_workerable.rb 51.85 % 84 27 14 13 0.52
app/models/concerns/product_build_lists/statusable.rb 86.36 % 115 44 38 6 1.00
app/models/concerns/project/default_branch.rb 43.33 % 79 30 13 17 0.50
app/models/concerns/project/finders.rb 80.00 % 72 35 28 7 1.03
app/models/concerns/regeneration_status.rb 71.43 % 44 21 15 6 2.00
app/models/concerns/time_living.rb 57.14 % 28 14 8 6 1.00
app/models/concerns/token_authenticatable.rb 76.47 % 31 17 13 4 4.00
app/models/concerns/url_helper.rb 40.00 % 7 5 2 3 0.40
app/models/concerns/web_hooks.rb 100.00 % 55 30 30 0 1.93
app/models/concerns/wiki.rb 64.71 % 31 17 11 6 0.76
app/models/event_log.rb 55.00 % 35 20 11 9 0.65
app/models/flash_notify.rb 75.00 % 22 12 9 3 0.75
app/models/git_hook.rb 28.26 % 83 46 13 33 0.28
app/models/group.rb 77.50 % 72 40 31 9 0.78
app/models/hook.rb 28.79 % 145 66 19 47 0.29
app/models/invite.rb 66.67 % 44 24 16 8 0.67
app/models/issue.rb 54.88 % 153 82 45 37 0.60
app/models/key_pair.rb 32.65 % 81 49 16 33 0.33
app/models/label.rb 100.00 % 11 8 8 0 1.00
app/models/labeling.rb 100.00 % 4 3 3 0 1.00
app/models/mass_build.rb 55.56 % 190 99 55 44 0.80
app/models/platform.rb 59.30 % 322 172 102 70 1.52
app/models/platform_arch_setting.rb 92.31 % 18 13 12 1 0.92
app/models/platform_content.rb 27.27 % 89 44 12 32 0.27
app/models/product.rb 50.00 % 54 34 17 17 0.56
app/models/product_build_list.rb 88.24 % 60 34 30 4 0.88
app/models/project.rb 41.12 % 352 214 88 126 0.66
app/models/project_import.rb 100.00 % 11 7 7 0 1.00
app/models/project_statistic.rb 100.00 % 8 5 5 0 1.00
app/models/project_tag.rb 87.50 % 17 8 7 1 0.88
app/models/project_to_repository.rb 80.00 % 38 20 16 4 1.15
app/models/pull_request.rb 37.50 % 271 144 54 90 0.38
app/models/relation.rb 52.94 % 57 34 18 16 1.74
app/models/repository.rb 48.11 % 199 106 51 55 0.48
app/models/repository_status.rb 100.00 % 81 49 49 0 1.22
app/models/rpm_build_node.rb 65.22 % 35 23 15 8 0.65
app/models/search.rb 57.14 % 29 14 8 6 0.79
app/models/settings_notifier.rb 100.00 % 6 3 3 0 1.00
app/models/ssh_key.rb 41.67 % 63 36 15 21 0.42
app/models/statistic.rb 91.67 % 106 36 33 3 1.25
app/models/subscribe.rb 43.24 % 70 37 16 21 0.43
app/models/token.rb 83.33 % 30 18 15 3 0.83
app/models/user.rb 66.36 % 192 107 71 36 1.46
app/models/user_builds_setting.rb 100.00 % 8 4 4 0 1.00
app/models/wiki_page.rb 83.33 % 11 6 5 1 0.83
app/policies/advisory_policy.rb 70.00 % 24 10 7 3 0.70
app/policies/application_policy.rb 57.58 % 178 66 38 28 0.95
app/policies/arch_policy.rb 66.67 % 6 3 2 1 0.67
app/policies/build_list_policy.rb 53.85 % 161 52 28 24 0.65
app/policies/collaborator_policy.rb 66.67 % 10 3 2 1 0.67
app/policies/comment_policy.rb 60.00 % 21 10 6 4 0.60
app/policies/group_policy.rb 65.52 % 51 29 19 10 0.66
app/policies/hook_policy.rb 77.78 % 18 9 7 2 0.78
app/policies/invite_policy.rb 60.00 % 9 5 3 2 0.60
app/policies/issue_policy.rb 36.84 % 34 19 7 12 0.37
app/policies/key_pair_policy.rb 57.14 % 16 7 4 3 0.57
app/policies/mass_build_policy.rb 69.23 % 42 13 9 4 0.69
app/policies/platform_policy.rb 61.82 % 157 55 34 21 0.65
app/policies/product_build_list_policy.rb 58.82 % 47 17 10 7 0.59
app/policies/product_policy.rb 64.29 % 37 14 9 5 0.64
app/policies/project_policy.rb 61.76 % 173 68 42 26 0.68
app/policies/pull_request_policy.rb 58.82 % 37 17 10 7 0.59
app/policies/repository_policy.rb 66.67 % 84 42 28 14 0.67
app/policies/search_policy.rb 66.67 % 7 3 2 1 0.67
app/policies/settings_notifier_policy.rb 66.67 % 22 3 2 1 0.67
app/policies/ssh_key_policy.rb 66.67 % 10 3 2 1 0.67
app/policies/statistic_policy.rb 66.67 % 7 3 2 1 0.67
app/policies/subscribe_policy.rb 36.36 % 22 11 4 7 0.36
app/policies/token_policy.rb 75.00 % 18 8 6 2 0.75
app/policies/user_builds_setting_policy.rb 66.67 % 10 3 2 1 0.67
app/policies/user_policy.rb 66.67 % 49 15 10 5 0.67
app/presenters/abf_worker_status_presenter.rb 21.88 % 53 32 7 25 0.22
app/presenters/api/v1/repository_package_presenter.rb 47.06 % 54 17 8 9 0.47
app/presenters/application_presenter.rb 100.00 % 55 1 1 0 1.00
app/presenters/comment_presenter.rb 27.27 % 120 66 18 48 0.27
app/presenters/git_presenters/commit_as_message_presenter.rb 28.79 % 112 66 19 47 0.29
app/presenters/statistic_presenter.rb 42.86 % 127 49 21 28 0.43
app/services/abf_worker_service/base.rb 29.55 % 83 44 13 31 0.41
app/services/abf_worker_service/container.rb 42.86 % 82 28 12 16 0.43
app/services/abf_worker_service/platform_metadata.rb 38.10 % 60 21 8 13 0.38
app/services/abf_worker_service/repository.rb 25.00 % 93 40 10 30 0.25
app/services/abf_worker_service/repository_metadata.rb 40.00 % 64 20 8 12 0.40
app/services/abf_worker_service/rpm.rb 18.49 % 242 119 22 97 0.18
app/services/file_store_service.rb 28.57 % 70 35 10 25 0.29
lib/ext/bootstrap_link_renderer.rb 100.00 % 62 0 0 0 0.00
lib/ext/core/object.rb 40.00 % 10 5 2 3 0.40
lib/ext/core/string.rb 34.78 % 36 23 8 15 20.52
lib/ext/git/gollum.rb 21.05 % 75 38 8 30 0.21
lib/ext/git/grit.rb 39.66 % 109 58 23 35 0.40
lib/ext/paperclip.rb 66.67 % 30 18 12 6 0.67
lib/ext/posix_spawn.rb 80.95 % 101 42 34 8 12.17
lib/ext/rails/render_errors_in_forms.rb 25.00 % 7 4 1 3 0.25
lib/ext/rails/reserved_name_validator.rb 87.50 % 38 8 7 1 56.63
lib/ext/rosa/constraints.rb 57.14 % 38 21 12 9 1.00
lib/ext/wiki/blob_entry.rb 25.00 % 11 8 2 6 0.25
lib/plugins.rb 100.00 % 4 3 3 0 3.00
lib/plugins/grack.rb 100.00 % 7 5 5 0 1.00
lib/plugins/grack/auth.rb 45.45 % 23 11 5 6 0.45
lib/plugins/grack/base.rb 48.39 % 60 31 15 16 0.48
lib/plugins/grack/handler.rb 60.00 % 17 10 6 4 0.60
lib/plugins/redcarpet.rb 100.00 % 1 1 1 0 1.00
lib/plugins/redcarpet/render/gitlab_html.rb 38.10 % 52 21 8 13 0.38
lib/plugins/rosa_presenter.rb 100.00 % 10 6 6 0 1.00
lib/plugins/rosa_presenter/activation.rb 100.00 % 13 7 7 0 1.29
lib/plugins/rosa_presenter/base.rb 60.61 % 62 33 20 13 0.67
lib/plugins/rpm.rb 35.71 % 53 28 10 18 0.36

Controllers ( 29.86% covered at 0.32 hits/line )

60 files in total.
2686 relevant lines, 802 lines covered and 1884 lines missed. ( 29.86% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
app/controllers/advisories_controller.rb 28.57 % 34 21 6 15 0.29
app/controllers/api/v1/advisories_controller.rb 46.43 % 52 28 13 15 0.46
app/controllers/api/v1/arches_controller.rb 60.00 % 9 5 3 2 0.60
app/controllers/api/v1/base_controller.rb 30.43 % 127 69 21 48 0.30
app/controllers/api/v1/build_lists_controller.rb 33.33 % 96 51 17 34 0.33
app/controllers/api/v1/groups_controller.rb 45.95 % 67 37 17 20 0.46
app/controllers/api/v1/issues_controller.rb 25.37 % 112 67 17 50 0.25
app/controllers/api/v1/jobs_controller.rb 19.72 % 130 71 14 57 0.20
app/controllers/api/v1/maintainers_controller.rb 60.00 % 11 5 3 2 0.60
app/controllers/api/v1/platforms_controller.rb 37.50 % 96 56 21 35 0.38
app/controllers/api/v1/product_build_lists_controller.rb 42.42 % 59 33 14 19 0.42
app/controllers/api/v1/products_controller.rb 71.43 % 29 14 10 4 0.71
app/controllers/api/v1/projects_controller.rb 41.30 % 85 46 19 27 0.41
app/controllers/api/v1/pull_requests_controller.rb 20.18 % 172 109 22 87 0.20
app/controllers/api/v1/repositories_controller.rb 31.34 % 125 67 21 46 0.31
app/controllers/api/v1/search_controller.rb 25.00 % 12 8 2 6 0.25
app/controllers/api/v1/users_controller.rb 41.18 % 63 34 14 20 0.41
app/controllers/application_controller.rb 63.41 % 165 82 52 30 1.11
app/controllers/autocompletes_controller.rb 37.93 % 68 29 11 18 0.38
app/controllers/concerns/api/v1/issueable.rb 55.56 % 45 18 10 8 0.56
app/controllers/concerns/strong_params.rb 62.50 % 16 8 5 3 0.63
app/controllers/groups/base_controller.rb 71.43 % 13 7 5 2 0.71
app/controllers/groups/members_controller.rb 25.00 % 38 24 6 18 0.25
app/controllers/groups/profile_controller.rb 25.42 % 93 59 15 44 0.25
app/controllers/home_controller.rb 16.67 % 112 60 10 50 0.17
app/controllers/pages_controller.rb 50.00 % 22 10 5 5 0.50
app/controllers/platforms/base_controller.rb 66.67 % 11 6 4 2 0.67
app/controllers/platforms/contents_controller.rb 35.29 % 28 17 6 11 0.35
app/controllers/platforms/key_pairs_controller.rb 26.32 % 31 19 5 14 0.26
app/controllers/platforms/maintainers_controller.rb 50.00 % 16 10 5 5 0.50
app/controllers/platforms/mass_builds_controller.rb 19.74 % 126 76 15 61 0.20
app/controllers/platforms/platforms_controller.rb 20.91 % 176 110 23 87 0.21
app/controllers/platforms/product_build_lists_controller.rb 28.57 % 123 70 20 50 0.29
app/controllers/platforms/products_controller.rb 40.00 % 73 40 16 24 0.40
app/controllers/platforms/repositories_controller.rb 25.93 % 192 108 28 80 0.26
app/controllers/platforms/tokens_controller.rb 34.38 % 62 32 11 21 0.34
app/controllers/projects/base_controller.rb 76.47 % 26 17 13 4 1.12
app/controllers/projects/build_lists_controller.rb 29.20 % 246 137 40 97 0.35
app/controllers/projects/collaborators_controller.rb 33.33 % 78 45 15 30 0.33
app/controllers/projects/comments_controller.rb 38.24 % 65 34 13 21 0.38
app/controllers/projects/commit_subscribes_controller.rb 41.18 % 28 17 7 10 0.41
app/controllers/projects/git/base_controller.rb 76.92 % 22 13 10 3 0.77
app/controllers/projects/git/blobs_controller.rb 43.48 % 40 23 10 13 0.43
app/controllers/projects/git/commits_controller.rb 12.90 % 50 31 4 27 0.13
app/controllers/projects/git/trees_controller.rb 25.37 % 110 67 17 50 0.25
app/controllers/projects/hooks_controller.rb 40.63 % 56 32 13 19 0.41
app/controllers/projects/issues_controller.rb 22.92 % 176 96 22 74 0.23
app/controllers/projects/projects_controller.rb 18.57 % 214 140 26 114 0.19
app/controllers/projects/pull_requests_controller.rb 17.27 % 169 110 19 91 0.17
app/controllers/projects/subscribes_controller.rb 38.89 % 31 18 7 11 0.39
app/controllers/projects/wiki_controller.rb 18.58 % 287 183 34 149 0.19
app/controllers/robots_controller.rb 75.00 % 7 4 3 1 0.75
app/controllers/search_controller.rb 55.56 % 13 9 5 4 0.56
app/controllers/statistics_controller.rb 11.63 % 80 43 5 38 0.12
app/controllers/users/base_controller.rb 66.67 % 16 9 6 3 0.67
app/controllers/users/profile_controller.rb 25.00 % 28 16 4 12 0.25
app/controllers/users/registrations_controller.rb 25.00 % 58 36 9 27 0.25
app/controllers/users/settings_controller.rb 27.12 % 97 59 16 43 0.27
app/controllers/users/ssh_keys_controller.rb 40.91 % 38 22 9 13 0.41
app/controllers/users/users_controller.rb 47.37 % 32 19 9 10 0.47

Models ( 53.82% covered at 0.94 hits/line )

75 files in total.
3103 relevant lines, 1670 lines covered and 1433 lines missed. ( 53.82% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
app/models/activity_feed.rb 93.33 % 22 15 14 1 4.93
app/models/advisory.rb 47.92 % 74 48 23 25 0.48
app/models/arch.rb 100.00 % 9 5 5 0 1.00
app/models/avatar.rb 100.00 % 18 11 11 0 1.27
app/models/build_list.rb 59.32 % 738 354 210 144 1.08
app/models/build_list/filter.rb 20.00 % 102 50 10 40 0.20
app/models/build_list/item.rb 50.00 % 42 18 9 9 0.50
app/models/build_list/package.rb 56.10 % 84 41 23 18 0.56
app/models/collaborator.rb 39.53 % 154 86 34 52 0.40
app/models/comment.rb 24.41 % 217 127 31 96 0.24
app/models/concerns/abf_worker_methods.rb 44.12 % 77 34 15 19 0.44
app/models/concerns/acts_like_member.rb 75.00 % 37 16 12 4 1.81
app/models/concerns/autostart.rb 85.71 % 29 14 12 2 0.93
app/models/concerns/build_list_observer.rb 65.00 % 45 20 13 7 1.15
app/models/concerns/commit_and_version.rb 78.95 % 33 19 15 4 2.05
app/models/concerns/default_branchable.rb 100.00 % 9 4 4 0 1.50
app/models/concerns/empty_metadata.rb 71.43 % 13 7 5 2 0.86
app/models/concerns/event_loggable.rb 62.50 % 32 16 10 6 4.69
app/models/concerns/external_nodable.rb 100.00 % 12 5 5 0 1.40
app/models/concerns/feed/build_list.rb 70.00 % 44 10 7 3 0.90
app/models/concerns/feed/comment.rb 30.77 % 72 26 8 18 0.31
app/models/concerns/feed/git.rb 5.56 % 82 36 2 34 0.06
app/models/concerns/feed/issue.rb 46.15 % 70 26 12 14 0.46
app/models/concerns/feed/user.rb 100.00 % 17 7 7 0 4.29
app/models/concerns/file_store_clean.rb 56.25 % 29 16 9 7 1.06
app/models/concerns/flash_notify/finders.rb 76.92 % 33 13 10 3 0.77
app/models/concerns/git.rb 31.14 % 298 167 52 115 0.73
app/models/concerns/owner.rb 100.00 % 10 6 6 0 4.67
app/models/concerns/personal_repository.rb 92.00 % 38 25 23 2 7.40
app/models/concerns/platform/finders.rb 91.67 % 50 24 22 2 3.75
app/models/concerns/product_build_lists/abf_workerable.rb 51.85 % 84 27 14 13 0.52
app/models/concerns/product_build_lists/statusable.rb 86.36 % 115 44 38 6 1.00
app/models/concerns/project/default_branch.rb 43.33 % 79 30 13 17 0.50
app/models/concerns/project/finders.rb 80.00 % 72 35 28 7 1.03
app/models/concerns/regeneration_status.rb 71.43 % 44 21 15 6 2.00
app/models/concerns/time_living.rb 57.14 % 28 14 8 6 1.00
app/models/concerns/token_authenticatable.rb 76.47 % 31 17 13 4 4.00
app/models/concerns/url_helper.rb 40.00 % 7 5 2 3 0.40
app/models/concerns/web_hooks.rb 100.00 % 55 30 30 0 1.93
app/models/concerns/wiki.rb 64.71 % 31 17 11 6 0.76
app/models/event_log.rb 55.00 % 35 20 11 9 0.65
app/models/flash_notify.rb 75.00 % 22 12 9 3 0.75
app/models/git_hook.rb 28.26 % 83 46 13 33 0.28
app/models/group.rb 77.50 % 72 40 31 9 0.78
app/models/hook.rb 28.79 % 145 66 19 47 0.29
app/models/invite.rb 66.67 % 44 24 16 8 0.67
app/models/issue.rb 54.88 % 153 82 45 37 0.60
app/models/key_pair.rb 32.65 % 81 49 16 33 0.33
app/models/label.rb 100.00 % 11 8 8 0 1.00
app/models/labeling.rb 100.00 % 4 3 3 0 1.00
app/models/mass_build.rb 55.56 % 190 99 55 44 0.80
app/models/platform.rb 59.30 % 322 172 102 70 1.52
app/models/platform_arch_setting.rb 92.31 % 18 13 12 1 0.92
app/models/platform_content.rb 27.27 % 89 44 12 32 0.27
app/models/product.rb 50.00 % 54 34 17 17 0.56
app/models/product_build_list.rb 88.24 % 60 34 30 4 0.88
app/models/project.rb 41.12 % 352 214 88 126 0.66
app/models/project_import.rb 100.00 % 11 7 7 0 1.00
app/models/project_statistic.rb 100.00 % 8 5 5 0 1.00
app/models/project_tag.rb 87.50 % 17 8 7 1 0.88
app/models/project_to_repository.rb 80.00 % 38 20 16 4 1.15
app/models/pull_request.rb 37.50 % 271 144 54 90 0.38
app/models/relation.rb 52.94 % 57 34 18 16 1.74
app/models/repository.rb 48.11 % 199 106 51 55 0.48
app/models/repository_status.rb 100.00 % 81 49 49 0 1.22
app/models/rpm_build_node.rb 65.22 % 35 23 15 8 0.65
app/models/search.rb 57.14 % 29 14 8 6 0.79
app/models/settings_notifier.rb 100.00 % 6 3 3 0 1.00
app/models/ssh_key.rb 41.67 % 63 36 15 21 0.42
app/models/statistic.rb 91.67 % 106 36 33 3 1.25
app/models/subscribe.rb 43.24 % 70 37 16 21 0.43
app/models/token.rb 83.33 % 30 18 15 3 0.83
app/models/user.rb 66.36 % 192 107 71 36 1.46
app/models/user_builds_setting.rb 100.00 % 8 4 4 0 1.00
app/models/wiki_page.rb 83.33 % 11 6 5 1 0.83

Helpers ( 24.83% covered at 0.25 hits/line )

29 files in total.
1027 relevant lines, 255 lines covered and 772 lines missed. ( 24.83% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
app/helpers/active_admin/admin_helper.rb 75.00 % 10 4 3 1 0.75
app/helpers/activity_feeds_helper.rb 33.33 % 34 18 6 12 0.33
app/helpers/advisories_helper.rb 33.33 % 21 12 4 8 0.33
app/helpers/application_helper.rb 18.03 % 121 61 11 50 0.18
app/helpers/avatar_helper.rb 40.00 % 8 5 2 3 0.40
app/helpers/build_lists_helper.rb 26.06 % 336 142 37 105 0.26
app/helpers/comments_helper.rb 27.78 % 29 18 5 13 0.28
app/helpers/commit_helper.rb 15.15 % 196 132 20 112 0.15
app/helpers/datatable_helper.rb 57.14 % 14 7 4 3 0.57
app/helpers/devise_helper.rb 30.00 % 20 10 3 7 0.30
app/helpers/diff_helper.rb 25.95 % 332 158 41 117 0.26
app/helpers/file_store_helper.rb 33.33 % 17 9 3 6 0.33
app/helpers/git_helper.rb 11.65 % 161 103 12 91 0.12
app/helpers/gitlab_markdown_helper.rb 25.58 % 102 43 11 32 0.26
app/helpers/hooks_helper.rb 100.00 % 2 1 1 0 1.00
app/helpers/issues_helper.rb 33.33 % 8 6 2 4 0.33
app/helpers/key_pairs_helper.rb 50.00 % 8 4 2 2 0.50
app/helpers/markdown_helper.rb 25.00 % 177 64 16 48 0.25
app/helpers/mass_build_helper.rb 40.00 % 25 10 4 6 0.40
app/helpers/paginate_helper.rb 21.05 % 34 19 4 15 0.21
app/helpers/platforms_helper.rb 28.00 % 46 25 7 18 0.28
app/helpers/product_build_lists_helper.rb 66.67 % 7 3 2 1 0.67
app/helpers/projects_helper.rb 28.30 % 106 53 15 38 0.28
app/helpers/pull_request_helper.rb 22.22 % 61 36 8 28 0.22
app/helpers/repositories_helper.rb 100.00 % 3 1 1 0 1.00
app/helpers/statistics_helper.rb 50.00 % 9 4 2 2 0.50
app/helpers/title_helper.rb 33.33 % 19 12 4 8 0.33
app/helpers/users_helper.rb 33.33 % 21 12 4 8 0.33
app/helpers/wiki_helper.rb 38.18 % 106 55 21 34 0.38

Mailers ( 32.73% covered at 0.33 hits/line )

1 files in total.
55 relevant lines, 18 lines covered and 37 lines missed. ( 32.73% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
app/mailers/user_mailer.rb 32.73 % 121 55 18 37 0.33

Policies ( 60.45% covered at 0.68 hits/line )

26 files in total.
488 relevant lines, 295 lines covered and 193 lines missed. ( 60.45% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
app/policies/advisory_policy.rb 70.00 % 24 10 7 3 0.70
app/policies/application_policy.rb 57.58 % 178 66 38 28 0.95
app/policies/arch_policy.rb 66.67 % 6 3 2 1 0.67
app/policies/build_list_policy.rb 53.85 % 161 52 28 24 0.65
app/policies/collaborator_policy.rb 66.67 % 10 3 2 1 0.67
app/policies/comment_policy.rb 60.00 % 21 10 6 4 0.60
app/policies/group_policy.rb 65.52 % 51 29 19 10 0.66
app/policies/hook_policy.rb 77.78 % 18 9 7 2 0.78
app/policies/invite_policy.rb 60.00 % 9 5 3 2 0.60
app/policies/issue_policy.rb 36.84 % 34 19 7 12 0.37
app/policies/key_pair_policy.rb 57.14 % 16 7 4 3 0.57
app/policies/mass_build_policy.rb 69.23 % 42 13 9 4 0.69
app/policies/platform_policy.rb 61.82 % 157 55 34 21 0.65
app/policies/product_build_list_policy.rb 58.82 % 47 17 10 7 0.59
app/policies/product_policy.rb 64.29 % 37 14 9 5 0.64
app/policies/project_policy.rb 61.76 % 173 68 42 26 0.68
app/policies/pull_request_policy.rb 58.82 % 37 17 10 7 0.59
app/policies/repository_policy.rb 66.67 % 84 42 28 14 0.67
app/policies/search_policy.rb 66.67 % 7 3 2 1 0.67
app/policies/settings_notifier_policy.rb 66.67 % 22 3 2 1 0.67
app/policies/ssh_key_policy.rb 66.67 % 10 3 2 1 0.67
app/policies/statistic_policy.rb 66.67 % 7 3 2 1 0.67
app/policies/subscribe_policy.rb 36.36 % 22 11 4 7 0.36
app/policies/token_policy.rb 75.00 % 18 8 6 2 0.75
app/policies/user_builds_setting_policy.rb 66.67 % 10 3 2 1 0.67
app/policies/user_policy.rb 66.67 % 49 15 10 5 0.67

Services ( 27.04% covered at 0.29 hits/line )

7 files in total.
307 relevant lines, 83 lines covered and 224 lines missed. ( 27.04% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
app/services/abf_worker_service/base.rb 29.55 % 83 44 13 31 0.41
app/services/abf_worker_service/container.rb 42.86 % 82 28 12 16 0.43
app/services/abf_worker_service/platform_metadata.rb 38.10 % 60 21 8 13 0.38
app/services/abf_worker_service/repository.rb 25.00 % 93 40 10 30 0.25
app/services/abf_worker_service/repository_metadata.rb 40.00 % 64 20 8 12 0.40
app/services/abf_worker_service/rpm.rb 18.49 % 242 119 22 97 0.18
app/services/file_store_service.rb 28.57 % 70 35 10 25 0.29

Presenters ( 32.03% covered at 0.32 hits/line )

6 files in total.
231 relevant lines, 74 lines covered and 157 lines missed. ( 32.03% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
app/presenters/abf_worker_status_presenter.rb 21.88 % 53 32 7 25 0.22
app/presenters/api/v1/repository_package_presenter.rb 47.06 % 54 17 8 9 0.47
app/presenters/application_presenter.rb 100.00 % 55 1 1 0 1.00
app/presenters/comment_presenter.rb 27.27 % 120 66 18 48 0.27
app/presenters/git_presenters/commit_as_message_presenter.rb 28.79 % 112 66 19 47 0.29
app/presenters/statistic_presenter.rb 42.86 % 127 49 21 28 0.43

Ungrouped ( 39.61% covered at 2.03 hits/line )

52 files in total.
861 relevant lines, 341 lines covered and 520 lines missed. ( 39.61% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
app/admin/builders.rb 10.53 % 30 19 2 17 0.11
app/admin/dashboard.rb 20.00 % 30 15 3 12 0.20
app/admin/event_logs.rb 25.00 % 37 24 6 18 0.25
app/admin/flash_notifies.rb 27.78 % 29 18 5 13 0.28
app/admin/resque.rb 100.00 % 3 2 2 0 1.00
app/admin/users.rb 35.71 % 66 42 15 27 0.36
app/jobs/abf_worker/base_observer.rb 55.56 % 42 27 15 12 0.56
app/jobs/abf_worker/iso_worker_observer.rb 35.71 % 31 14 5 9 0.36
app/jobs/abf_worker/publish_observer.rb 14.55 % 93 55 8 47 0.15
app/jobs/abf_worker/rpm_worker_observer.rb 18.03 % 112 61 11 50 0.18
app/jobs/autostart_builds_daily_job.rb 50.00 % 6 4 2 2 0.50
app/jobs/autostart_builds_once_every_twelve_hours_job.rb 50.00 % 6 4 2 2 0.50
app/jobs/autostart_builds_weekly_job.rb 50.00 % 6 4 2 2 0.50
app/jobs/autostart_regens_daily_job.rb 66.67 % 5 3 2 1 0.67
app/jobs/autostart_regens_weekly_job.rb 66.67 % 5 3 2 1 0.67
app/jobs/build_lists/build_canceling_destroy_job.rb 75.00 % 7 4 3 1 0.75
app/jobs/build_lists/clean_buildroot_job.rb 40.00 % 31 15 6 9 0.40
app/jobs/build_lists/create_container_job.rb 57.14 % 12 7 4 3 0.57
app/jobs/build_lists/dependent_packages_job.rb 12.50 % 61 32 4 28 0.13
app/jobs/clean_api_defender_statistics_job.rb 37.50 % 17 8 3 5 0.38
app/jobs/clean_rpm_build_node_job.rb 60.00 % 10 5 3 2 0.60
app/jobs/clean_temp_pull_requests_job.rb 60.00 % 8 5 3 2 0.60
app/jobs/clear_stale_builders_job.rb 75.00 % 9 4 3 1 0.75
app/jobs/clear_unused_invites_job.rb 75.00 % 7 4 3 1 0.75
app/jobs/create_empty_metadata_job.rb 28.21 % 72 39 11 28 0.28
app/jobs/destroy_project_from_repository_job.rb 50.00 % 8 4 2 2 0.50
app/jobs/publish_task_manager_job.rb 38.10 % 42 21 8 13 0.38
app/jobs/remove_outdated_items_job.rb 11.76 % 23 17 2 15 0.12
app/jobs/restart_nodes_job.rb 50.00 % 11 6 3 3 0.50
app/jobs/run_extra_mass_builds_job.rb 42.86 % 30 14 6 8 0.43
lib/ext/bootstrap_link_renderer.rb 100.00 % 62 0 0 0 0.00
lib/ext/core/object.rb 40.00 % 10 5 2 3 0.40
lib/ext/core/string.rb 34.78 % 36 23 8 15 20.52
lib/ext/git/gollum.rb 21.05 % 75 38 8 30 0.21
lib/ext/git/grit.rb 39.66 % 109 58 23 35 0.40
lib/ext/paperclip.rb 66.67 % 30 18 12 6 0.67
lib/ext/posix_spawn.rb 80.95 % 101 42 34 8 12.17
lib/ext/rails/render_errors_in_forms.rb 25.00 % 7 4 1 3 0.25
lib/ext/rails/reserved_name_validator.rb 87.50 % 38 8 7 1 56.63
lib/ext/rosa/constraints.rb 57.14 % 38 21 12 9 1.00
lib/ext/wiki/blob_entry.rb 25.00 % 11 8 2 6 0.25
lib/plugins.rb 100.00 % 4 3 3 0 3.00
lib/plugins/grack.rb 100.00 % 7 5 5 0 1.00
lib/plugins/grack/auth.rb 45.45 % 23 11 5 6 0.45
lib/plugins/grack/base.rb 48.39 % 60 31 15 16 0.48
lib/plugins/grack/handler.rb 60.00 % 17 10 6 4 0.60
lib/plugins/redcarpet.rb 100.00 % 1 1 1 0 1.00
lib/plugins/redcarpet/render/gitlab_html.rb 38.10 % 52 21 8 13 0.38
lib/plugins/rosa_presenter.rb 100.00 % 10 6 6 0 1.00
lib/plugins/rosa_presenter/activation.rb 100.00 % 13 7 7 0 1.29
lib/plugins/rosa_presenter/base.rb 60.61 % 62 33 20 13 0.67
lib/plugins/rpm.rb 35.71 % 53 28 10 18 0.36

app/admin/builders.rb

10.53% lines covered

19 relevant lines. 2 lines covered and 17 lines missed.
    
  1. 1 ActiveAdmin.register_page 'Builders' do
  2. 1 content do
  3. div class: 'index_as_table' do
  4. table_for RpmBuildNode.all.to_a.select { |b| b.get_ttl > 0 }, class: "index_table index" do
  5. column :id
  6. column :user_id do |b|
  7. u = User.find(b.user_id) rescue nil
  8. if u
  9. link_to u.uname, admin_user_path(u.id)
  10. else
  11. 'None'
  12. end
  13. end
  14. column :system
  15. column :host
  16. column :busy_workers
  17. column :query_string do |b|
  18. b.query_string.present? ? b.query_string : '-'
  19. end
  20. column 'Last build ID' do |b|
  21. if b.last_build_id.present?
  22. link_to b.last_build_id, build_list_path(b.last_build_id)
  23. else
  24. 'None'
  25. end
  26. end
  27. end
  28. end
  29. end
  30. end

app/admin/dashboard.rb

20.0% lines covered

15 relevant lines. 3 lines covered and 12 lines missed.
    
  1. 1 ActiveAdmin.register_page 'Dashboard' do
  2. 1 menu priority: 1
  3. 1 content do
  4. columns do
  5. column do
  6. panel "Deploy Information" do
  7. require 'deploy_info'
  8. abf = "https://abf.io/abf/rosa-build/"
  9. #jenkins = "https://ci.shuttlerock.com/"
  10. attributes_table_for DeployInfo do
  11. row('Branch') { link_to DeployInfo::BRANCH, "#{abf}tree/#{DeployInfo::BRANCH}" }
  12. row('Commit') { link_to DeployInfo::GIT_COMMIT, "#{abf}commit/#{DeployInfo::GIT_COMMIT}" }
  13. row('Build Number') { DeployInfo::BUILD_NUMBER }
  14. row('Build ID') { DeployInfo::BUILD_ID }
  15. row('Deployer') { DeployInfo::DEPLOYER }
  16. row(:message) { pre DeployInfo.message }
  17. end
  18. end # panel
  19. end # column
  20. end # columns
  21. end # content
  22. end

app/admin/event_logs.rb

25.0% lines covered

24 relevant lines. 6 lines covered and 18 lines missed.
    
  1. 1 ActiveAdmin.register EventLog do
  2. 1 menu parent: 'Misc'
  3. 1 actions :all, except: %i(create update new edit destroy)
  4. 1 controller do
  5. 1 def scoped_collection
  6. EventLog.includes(:user)
  7. end
  8. end
  9. 1 index do
  10. column :id
  11. column :kind
  12. column :created_at
  13. column :user
  14. column :ip
  15. column :protocol
  16. column('Description') do |el|
  17. msg = %w([)
  18. msg << I18n.t("event_log.controllers.#{el.controller.underscore}", default: el.controller) << "]"
  19. msg << I18n.t("event_log.actions.#{el.controller.underscore}.#{el.action}", default: :"event_log.actions.#{el.action}")
  20. if el.eventable_id.present? and el.eventable_type.present?
  21. msg << '' << I18n.t("activerecord.models.#{el.eventable_type.underscore}")
  22. msg << el.eventable_name
  23. msg << "(id##{el.eventable_id})" # link_to "id##{el.eventable_id}", el.eventable
  24. end
  25. msg << el.message.to_s
  26. msg.join(' ')
  27. end
  28. actions
  29. end
  30. end

app/admin/flash_notifies.rb

27.78% lines covered

18 relevant lines. 5 lines covered and 13 lines missed.
    
  1. 1 ActiveAdmin.register FlashNotify do
  2. 1 permit_params :body_ru, :body_en, :status, :published
  3. 1 menu parent: 'Misc'
  4. 1 index do
  5. column :id
  6. column(:body_en) do |fn|
  7. fn.body_en.truncate(18)
  8. end
  9. column(:body_ru) do |fn|
  10. fn.body_ru.truncate(18)
  11. end
  12. column :published
  13. actions
  14. end
  15. 1 form do |f|
  16. f.inputs do
  17. f.input :body_en
  18. f.input :body_ru
  19. f.input :status, as: :select, collection: FlashNotify::STATUSES, include_blank: false
  20. f.input :published
  21. end
  22. f.actions
  23. end
  24. end

app/admin/resque.rb

100.0% lines covered

2 relevant lines. 2 lines covered and 0 lines missed.
    
  1. 1 ActiveAdmin.register_page 'Resque' do
  2. 1 menu priority: 100, label: 'Resque', url: '/admin/resque/overview'
  3. end

app/admin/users.rb

35.71% lines covered

42 relevant lines. 15 lines covered and 27 lines missed.
    
  1. 1 ActiveAdmin.register User do
  2. 1 permit_params :uname, :name, :email, :password, :password_confirmation
  3. 1 menu priority: 2
  4. 1 filter :uname
  5. 1 filter :email
  6. 1 filter :role, as: :select, collection: User::EXTENDED_ROLES
  7. 1 filter :created_at
  8. 1 controller do
  9. 1 def update(options={}, &block)
  10. user_params = params[:user]
  11. resource.role = user_params.delete(:role)
  12. user_params.delete(:password) if user_params[:password].blank?
  13. user_params.delete(:password_confirmation) if user_params[:password_confirmation].blank?
  14. super
  15. end
  16. end
  17. 1 index do
  18. column :id
  19. column(:uname) do |user|
  20. link_to(user.uname, user_path(user))
  21. end
  22. column :email
  23. column :created_at
  24. column :role
  25. actions
  26. end
  27. 1 form do |f|
  28. f.inputs do
  29. f.input :name
  30. f.input :email
  31. f.input :uname
  32. f.input :role, as: :select, collection: User::EXTENDED_ROLES, include_blank: false
  33. f.input :password
  34. f.input :password_confirmation
  35. end
  36. f.actions
  37. end
  38. 1 action_item(:reset_token, only: :show) do
  39. link_to 'Reset token', reset_token_admin_user_path(resource),
  40. 'data-method' => :put,
  41. data: { confirm: 'Are you sure you want to reset token?' }
  42. end
  43. 1 action_item(:login_as, only: :show) do
  44. link_to 'Login as user', login_as_admin_user_path(resource)
  45. end
  46. 1 member_action :reset_token, :method => :put do
  47. resource.reset_authentication_token!
  48. flash[:info] = 'User token reseted successfully'
  49. redirect_to admin_user_path(resource)
  50. end
  51. 1 member_action :login_as do
  52. sign_in(resource, bypass: true)
  53. redirect_to root_path
  54. end
  55. end

app/controllers/advisories_controller.rb

28.57% lines covered

21 relevant lines. 6 lines covered and 15 lines missed.
    
  1. 1 class AdvisoriesController < ApplicationController
  2. 1 before_action :authenticate_user!
  3. 1 skip_before_action :authenticate_user! if APP_CONFIG['anonymous_access']
  4. 1 def index
  5. authorize :advisory
  6. @advisories = Advisory.includes(:platforms, :projects).search_like(params[:q]).distinct
  7. @advisories_count = @advisories.count
  8. @advisories = @advisories.paginate(page: current_page, per_page: Advisory.per_page)
  9. respond_to do |format|
  10. format.html
  11. format.json
  12. format.atom
  13. end
  14. end
  15. 1 def show
  16. authorize @advisory = Advisory.find_by(advisory_id: params[:id])
  17. @packages_info = @advisory.fetch_packages_info
  18. end
  19. 1 def search
  20. authorize :advisory
  21. @advisory = Advisory.by_update_type(params[:bl_type]).search_by_id(params[:query]).first
  22. if @advisory.nil?
  23. head 404
  24. else
  25. # respond_to do |format|
  26. # format.json { render @advisory }
  27. # end
  28. render @advisory
  29. end
  30. end
  31. end

app/controllers/api/v1/advisories_controller.rb

46.43% lines covered

28 relevant lines. 13 lines covered and 15 lines missed.
    
  1. 1 class Api::V1::AdvisoriesController < Api::V1::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 skip_before_action :authenticate_user!, only: %i(index show) if APP_CONFIG['anonymous_access']
  4. 1 before_action :load_advisory, only: %i(show update)
  5. 1 before_action :load_build_list, only: %i(create update)
  6. 1 def index
  7. authorize :advisory
  8. @advisories = Advisory.includes(:platforms, :projects).paginate(paginate_params)
  9. end
  10. 1 def show
  11. @packages_info = @advisory.fetch_packages_info
  12. end
  13. 1 def create
  14. authorize :advisory
  15. if @build_list.can_attach_to_advisory? &&
  16. @build_list.associate_and_create_advisory(advisory_params) &&
  17. @build_list.save
  18. render_json_response @build_list.advisory, 'Advisory has been created successfully'
  19. else
  20. render_validation_error @build_list.advisory, error_message(@build_list, 'Advisory has not been created')
  21. end
  22. end
  23. 1 def update
  24. if @advisory && @build_list.can_attach_to_advisory? &&
  25. @advisory.attach_build_list(@build_list) && @build_list.save
  26. render_json_response @advisory, "Build list '#{@build_list.id}' has been attached to advisory successfully"
  27. else
  28. render_validation_error @advisory, error_message(@build_list, 'Build list has not been attached to advisory')
  29. end
  30. end
  31. 1 protected
  32. 1 def advisory_params
  33. subject_params(Advisory)
  34. end
  35. 1 def load_build_list
  36. @build_list = BuildList.find params[:build_list_id]
  37. authorize @build_list.save_to_platform, :local_admin_manage?
  38. end
  39. 1 def load_advisory
  40. @advisory = Advisory.find_by(advisory_id: params[:id]) if params[:id]
  41. authorize @advisory if @advisory
  42. end
  43. end

app/controllers/api/v1/arches_controller.rb

60.0% lines covered

5 relevant lines. 3 lines covered and 2 lines missed.
    
  1. 1 class Api::V1::ArchesController < Api::V1::BaseController
  2. 1 before_action :authenticate_user! unless APP_CONFIG['anonymous_access']
  3. 1 def index
  4. authorize :arch
  5. @arches = Arch.order(:id).paginate(paginate_params)
  6. end
  7. end

app/controllers/api/v1/base_controller.rb

30.43% lines covered

69 relevant lines. 21 lines covered and 48 lines missed.
    
  1. 1 class Api::V1::BaseController < ApplicationController
  2. 1 include PaginateHelper
  3. 1 respond_to :json
  4. 1 helper_method :member_path
  5. 1 rescue_from Pundit::NotAuthorizedError do |exception|
  6. respond_to do |format|
  7. format.json { render json: {message: t('flash.exception_message')}.to_json, status: 403 }
  8. format.csv { render plain: t('flash.exception_message'), status: 403 }
  9. end
  10. end
  11. 1 protected
  12. 1 def set_csv_file_headers(file_name)
  13. headers['Content-Type'] = 'text/csv'
  14. headers['Content-disposition'] = "attachment; filename=\"#{file_name}.csv\""
  15. end
  16. 1 def set_streaming_headers
  17. # nginx doc: Setting this to "no" will allow unbuffered responses suitable for Comet and HTTP streaming applications
  18. headers['X-Accel-Buffering'] = 'no'
  19. headers['Cache-Control'] ||= 'no-cache'
  20. headers.delete 'Content-Length'
  21. end
  22. 1 def set_locale
  23. I18n.locale = :en
  24. end
  25. 1 def error_message(subject, message)
  26. [message, subject.errors.map(&:full_message)].flatten.join('. ')
  27. end
  28. 1 def create_subject(subject)
  29. authorize subject, :create?
  30. class_name = subject.class.name
  31. if subject.save
  32. render_json_response subject, "#{class_name} has been created successfully"
  33. else
  34. render_validation_error subject, "#{class_name} has not been created"
  35. end
  36. end
  37. 1 def update_member_in_subject(subject, relation = :relations)
  38. authorize subject, :update_member?
  39. role = params[:role]
  40. class_name = subject.class.name.downcase
  41. if member.present? && role.present? && subject.respond_to?(:owner) && subject.owner != member &&
  42. subject.send(relation).by_actor(member).update_all(role: role)
  43. render_json_response subject, "Role for #{member.class.name.downcase} '#{member.id} has been updated in #{class_name} successfully"
  44. else
  45. render_validation_error subject, "Role for member has not been updated in #{class_name}"
  46. end
  47. end
  48. 1 def add_member_to_subject(subject, role = 'admin')
  49. authorize subject, :add_member?
  50. class_name = subject.class.name.downcase
  51. if member.present? && subject.add_member(member, role)
  52. render_json_response subject, "#{member.class.to_s} '#{member.id}' has been added to #{class_name} successfully"
  53. else
  54. render_validation_error subject, "Member has not been added to #{class_name}"
  55. end
  56. end
  57. 1 def remove_member_from_subject(subject)
  58. authorize subject, :remove_member?
  59. class_name = subject.class.name.downcase
  60. if member.present? && subject.remove_member(member)
  61. render_json_response subject, "#{member.class.to_s} '#{member.id}' has been removed from #{class_name} successfully"
  62. else
  63. render_validation_error subject, "Member has not been removed from #{class_name}"
  64. end
  65. end
  66. 1 def destroy_subject(subject)
  67. authorize subject, :destroy?
  68. subject.destroy # later with resque
  69. render_json_response subject, "#{subject.class.name} has been destroyed successfully"
  70. end
  71. 1 def update_subject(subject)
  72. authorize subject, :update?
  73. class_name = subject.class.name
  74. if subject.update(subject_params(subject.class, subject))
  75. render_json_response subject, "#{class_name} has been updated successfully"
  76. else
  77. render_validation_error subject, "#{class_name} has not been updated"
  78. end
  79. end
  80. 1 def render_json_response(subject, message, status = 200)
  81. id = status != 200 ? nil : subject.id
  82. render json: {
  83. subject.class.name.underscore.to_sym => {
  84. id: id,
  85. message: message
  86. }
  87. }, status: status
  88. end
  89. 1 def render_validation_error(subject, message)
  90. render_json_response(subject, error_message(subject, message), 422)
  91. end
  92. 1 def member_path(subject)
  93. if subject.is_a?(User)
  94. api_v1_user_path(subject.id, format: :json)
  95. else
  96. api_v1_group_path(subject.id, format: :json)
  97. end
  98. end
  99. 1 private
  100. 1 def member
  101. if @member.blank? && %w(User Group).include?(params[:type])
  102. @member = params[:type].constantize.where(id: params[:member_id]).first
  103. end
  104. @member
  105. end
  106. end

app/controllers/api/v1/build_lists_controller.rb

33.33% lines covered

51 relevant lines. 17 lines covered and 34 lines missed.
    
  1. 1 class Api::V1::BuildListsController < Api::V1::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 before_action :load_build_list, only: %i(
  4. cancel
  5. create_container
  6. publish
  7. publish_into_testing
  8. reject_publish
  9. rerun_tests
  10. show
  11. )
  12. 1 skip_before_action :authenticate_user!, only: %i(show index) if APP_CONFIG['anonymous_access']
  13. 1 def show
  14. authorize @build_list
  15. respond_to :json
  16. end
  17. 1 def index
  18. authorize :build_list
  19. @project = Project.find(params[:project_id]) if params[:project_id].present?
  20. authorize @project, :show? if @project
  21. filter = BuildList::Filter.new(@project, current_user, params[:filter] || {})
  22. @build_lists = filter.find.includes(:build_for_platform,
  23. :save_to_repository,
  24. :save_to_platform,
  25. :project,
  26. :user,
  27. :arch)
  28. @build_lists = @build_lists.recent.paginate(paginate_params)
  29. respond_to :json
  30. end
  31. 1 def create
  32. save_to_repository = Repository.find_by(id: build_list_params[:save_to_repository_id])
  33. @build_list = current_user.build_lists.new(build_list_params)
  34. @build_list.save_to_platform = save_to_repository.platform if save_to_repository
  35. @build_list.priority = current_user.build_priority # User builds more priority than mass rebuild with zero priority
  36. create_subject @build_list
  37. end
  38. 1 def cancel
  39. authorize @build_list
  40. render_json :cancel
  41. end
  42. 1 def publish
  43. authorize @build_list
  44. @build_list.publisher = current_user
  45. render_json :publish
  46. end
  47. 1 def reject_publish
  48. authorize @build_list
  49. @build_list.publisher = current_user
  50. render_json :reject_publish
  51. end
  52. 1 def create_container
  53. authorize @build_list
  54. render_json :create_container, :publish_container
  55. end
  56. 1 def rerun_tests
  57. authorize @build_list
  58. render_json :rerun_tests
  59. end
  60. 1 def publish_into_testing
  61. authorize @build_list
  62. @build_list.publisher = current_user
  63. render_json :publish_into_testing
  64. end
  65. 1 private
  66. 1 def build_list_params
  67. subject_params(BuildList)
  68. end
  69. # Private: before_action hook which loads BuidList.
  70. 1 def load_build_list
  71. @build_list = BuildList.find params[:id]
  72. end
  73. 1 def render_json(action_name, action_method = nil)
  74. if @build_list.try("can_#{action_name}?") && @build_list.send(action_method || action_name)
  75. render_json_response @build_list, t("layout.build_lists.#{action_name}_success")
  76. else
  77. render_validation_error @build_list, t("layout.build_lists.#{action_name}_fail")
  78. end
  79. end
  80. end

app/controllers/api/v1/groups_controller.rb

45.95% lines covered

37 relevant lines. 17 lines covered and 20 lines missed.
    
  1. 1 class Api::V1::GroupsController < Api::V1::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 skip_before_action :authenticate_user!, only: [:show, :projects] if APP_CONFIG['anonymous_access']
  4. 1 before_action :load_group, except: %i(index create)
  5. 1 def index
  6. authorize :group
  7. @groups = current_user.groups.paginate(paginate_params)
  8. end
  9. 1 def show
  10. authorize @group
  11. end
  12. 1 def members
  13. authorize @group
  14. @members = @group.members.where('actor_id != ?', @group.owner_id)
  15. .order('name').paginate(paginate_params)
  16. end
  17. 1 def projects
  18. authorize @group
  19. render plain: @group.projects.pluck(:owner_uname, :name).map { |p| "#{p[0]}/#{p[1]}" }.join("\n")
  20. end
  21. 1 def update
  22. update_subject @group
  23. end
  24. 1 def destroy
  25. destroy_subject @group
  26. end
  27. 1 def create
  28. @group = current_user.own_groups.new
  29. @group.assign_attributes(group_params)
  30. create_subject @group
  31. end
  32. 1 def add_member
  33. params[:type] = 'User'
  34. add_member_to_subject @group, (params[:role] || 'admin')
  35. end
  36. 1 def remove_member
  37. params[:type] = 'User'
  38. remove_member_from_subject @group
  39. end
  40. 1 def update_member
  41. params[:type] = 'User'
  42. update_member_in_subject @group, :actors
  43. end
  44. 1 private
  45. 1 def group_params
  46. subject_params(Group, @group)
  47. end
  48. # Private: before_action hook which loads Group.
  49. 1 def load_group
  50. @group = Group.find params[:id]
  51. end
  52. end

app/controllers/api/v1/issues_controller.rb

25.37% lines covered

67 relevant lines. 17 lines covered and 50 lines missed.
    
  1. 1 class Api::V1::IssuesController < Api::V1::BaseController
  2. 1 include Api::V1::Issueable
  3. 1 before_action :authenticate_user!
  4. 1 skip_before_action :authenticate_user!, only: %i(index group_index show) if APP_CONFIG['anonymous_access']
  5. 1 before_action :load_group, only: :group_index
  6. 1 before_action :load_project
  7. 1 skip_before_action :load_project, only: %i(all_index user_index group_index)
  8. 1 before_action :load_issue, only: %i(show update index)
  9. 1 def index
  10. @issues = @project.issues
  11. render_issues_list
  12. end
  13. 1 def all_index
  14. authorize :issue, :index?
  15. project_ids = get_all_project_ids membered_projects.pluck(:id)
  16. @issues = Issue.where(project_id: project_ids)
  17. render_issues_list
  18. end
  19. 1 def user_index
  20. authorize :issue, :index?
  21. project_ids = get_all_project_ids current_user.projects.pluck(:id)
  22. @issues = Issue.where(project_id: project_ids)
  23. render_issues_list
  24. end
  25. 1 def group_index
  26. project_ids = @group.projects.pluck(:id)
  27. project_ids = membered_projects.where(id: project_ids).pluck(:id)
  28. @issues = Issue.where(project_id: project_ids)
  29. render_issues_list
  30. end
  31. 1 def show
  32. if @issue.pull_request
  33. redirect_to api_v1_project_pull_request_path(@project.id, @issue.serial_id)
  34. else
  35. respond_to :json
  36. end
  37. end
  38. 1 def create
  39. @issue = @project.issues.new
  40. @issue.assign_attributes subject_params(Issue, @issue)
  41. @issue.user = current_user
  42. create_subject @issue
  43. end
  44. 1 def update
  45. @issue.labelings.destroy_all if params[:update_labels] && policy(@project).write?
  46. if params[:issue] && status = params[:issue].delete(:status)
  47. @issue.set_close(current_user) if status == 'closed'
  48. @issue.set_open if status == 'open'
  49. end
  50. update_subject @issue
  51. end
  52. 1 private
  53. 1 def render_issues_list
  54. @issues = @issues.preload(:user, :assignee, :labels, :project).without_pull_requests
  55. if params[:status] == 'closed'
  56. @issues = @issues.closed
  57. else
  58. @issues = @issues.opened
  59. end
  60. if action_name == 'index' && params[:assignee].present?
  61. case params[:assignee]
  62. when 'none'
  63. @issues = @issues.where(assigned_id: nil)
  64. when '*'
  65. @issues = @issues.where('issues.assigned_id IS NOT NULL')
  66. else
  67. @issues = @issues.where('issues.assignees_issues.uname = ?', params[:assignee])
  68. end
  69. end
  70. if %w[all_index user_index group_index].include?(action_name)
  71. case params[:filter]
  72. when 'created'
  73. @issues = @issues.where(user_id: current_user)
  74. when 'all'
  75. else
  76. @issues = @issues.where(assignee_id: current_user)
  77. end
  78. else
  79. @issues.where('users.uname = ?', params[:creator]) if params[:creator].present?
  80. end
  81. if params[:labels].present?
  82. labels = params[:labels].split(',').map(&:strip).select(&:present?)
  83. @issues = @issues.where('labels.name IN (?)', labels)
  84. end
  85. sort = params[:sort] == 'updated' ? 'issues.updated_at' : 'issues.created_at'
  86. direction = params[:direction] == 'asc' ? 'ASC' : 'DESC'
  87. @issues = @issues.order("#{sort} #{direction}")
  88. @issues = @issues.where('issues.created_at >= to_timestamp(?)', params[:since]) if params[:since] =~ /\A\d+\z/
  89. @issues = @issues.paginate(paginate_params)
  90. respond_to do |format|
  91. format.json { render :index }
  92. end
  93. end
  94. end

app/controllers/api/v1/jobs_controller.rb

19.72% lines covered

71 relevant lines. 14 lines covered and 57 lines missed.
    
  1. 1 class Api::V1::JobsController < Api::V1::BaseController
  2. # QUEUES = %w(iso_worker_observer publish_observer rpm_worker_observer)
  3. # QUEUE_CLASSES = %w(AbfWorker::IsoWorkerObserver AbfWorker::PublishObserver AbfWorker::RpmWorkerObserver)
  4. 1 QUEUES = %w(rpm_worker_observer)
  5. 1 QUEUE_CLASSES = %w(AbfWorker::RpmWorkerObserver)
  6. 1 before_action :authenticate_user!
  7. 1 skip_after_action :verify_authorized
  8. 1 def shift
  9. job_shift_sem = Redis::Semaphore.new(:job_shift_lock)
  10. job_shift_sem.lock do
  11. build_lists = BuildList.scoped_to_arch(arch_ids).
  12. for_status([BuildList::BUILD_PENDING, BuildList::RERUN_TESTS]).
  13. for_platform(platform_ids).where(builder: nil)
  14. if current_user.system?
  15. build_lists = build_lists.where(external_nodes: ["", nil, "everything"])
  16. uid = build_lists.where(mass_build_id: nil).pluck('DISTINCT user_id').sample
  17. if !uid
  18. uid = build_lists.pluck('DISTINCT user_id').sample
  19. mass_build = true
  20. else
  21. mass_build = false
  22. end
  23. if uid
  24. if !mass_build
  25. @build_list = build_lists.where(user_id: uid, mass_build_id: nil).order(:created_at).first
  26. else
  27. @build_list = build_lists.where(user_id: uid).order(:created_at).first
  28. end
  29. end
  30. else
  31. tmp = build_lists.external_nodes(:owned).for_user(current_user).order(:created_at)
  32. @build_list = tmp.where(mass_build_id: nil).first
  33. @build_list ||= tmp.first
  34. if !@build_list
  35. tmp = BuildListPolicy::Scope.new(current_user, build_lists).owned.
  36. external_nodes(:everything).readonly(false).order(:created_at)
  37. @build_list ||= tmp.where(mass_build_id: nil).first
  38. @build_list ||= tmp.first
  39. end
  40. end
  41. set_builder
  42. end
  43. job = {
  44. worker_queue: '',
  45. worker_class: '',
  46. :worker_args => [@build_list.abf_worker_args]
  47. } if @build_list
  48. render json: { job: job }.to_json
  49. end
  50. 1 def statistics
  51. if params[:uid].present?
  52. RpmBuildNode.create(
  53. id: params[:uid],
  54. user_id: current_user.id,
  55. system: current_user.system?,
  56. worker_count: params[:worker_count],
  57. busy_workers: params[:busy_workers],
  58. host: params[:host].to_s,
  59. query_string: params[:query_string].to_s,
  60. last_build_id: params[:last_build_id].to_s
  61. ) rescue nil
  62. end
  63. head :ok
  64. end
  65. 1 def status
  66. if params[:key] =~ /\Aabfworker::(rpm|iso)-worker-[\d]+::live-inspector\z/
  67. status = Redis.current.get(params[:key])
  68. end
  69. render json: { status: status }.to_json
  70. end
  71. 1 def logs
  72. name = params[:name]
  73. if name =~ /abfworker::rpm-worker/
  74. if current_user.system? || current_user.id == BuildList.where(id: name.gsub(/[^\d]/, '')).first.try(:builder_id)
  75. BuildList.log_server.setex name, 15, params[:logs]
  76. end
  77. end
  78. head :ok
  79. end
  80. 1 def feedback
  81. worker_queue = params[:worker_queue]
  82. worker_class = params[:worker_class]
  83. if QUEUES.include?(worker_queue) && QUEUE_CLASSES.include?(worker_class)
  84. worker_args = (params[:worker_args] || []).first || {}
  85. worker_args = worker_args.merge(feedback_from_user: current_user.id)
  86. Resque.push worker_queue, 'class' => worker_class, 'args' => [worker_args]
  87. head :ok
  88. else
  89. head 403
  90. end
  91. end
  92. 1 protected
  93. 1 def platform_ids
  94. @platform_ids ||= begin
  95. platform_types = params[:platform_types].to_s.split(',') & APP_CONFIG['distr_types']
  96. platforms = params[:platforms].to_s.split(',')
  97. platforms = platforms.present? ? Platform.where(name: platforms).pluck(:id) : []
  98. platforms |= Platform.main.where(distrib_type: platform_types).pluck(:id) if !platform_types.empty?
  99. platforms
  100. end
  101. end
  102. 1 def arch_ids
  103. @arch_ids ||= begin
  104. arches = params[:arches].to_s.split(',')
  105. arches.present? ? Arch.where(name: arches).pluck(:id) : []
  106. end
  107. end
  108. 1 def set_builder
  109. return unless @build_list
  110. @build_list.builder = current_user
  111. if !@build_list.valid?
  112. Raven.capture_message('Invalid build list', extra: { id: @build_list.id, errors: @build_list.errors.map(&:full_message) })
  113. end
  114. @build_list.save(validate: false)
  115. end
  116. end

app/controllers/api/v1/maintainers_controller.rb

60.0% lines covered

5 relevant lines. 3 lines covered and 2 lines missed.
    
  1. 1 class Api::V1::MaintainersController < Api::V1::BaseController
  2. 1 before_action :authenticate_user! unless APP_CONFIG['anonymous_access']
  3. 1 def index
  4. authorize @platform = Platform.find(params[:platform_id]), :show?
  5. @maintainers = BuildList::Package.includes(:project)
  6. .actual.by_platform(@platform)
  7. .like_name(params[:package_name])
  8. .paginate(paginate_params)
  9. end
  10. end

app/controllers/api/v1/platforms_controller.rb

37.5% lines covered

56 relevant lines. 21 lines covered and 35 lines missed.
    
  1. 1 class Api::V1::PlatformsController < Api::V1::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 skip_before_action :authenticate_user!, only: :allowed
  4. 1 skip_before_action :authenticate_user!, only: [:show, :platforms_for_build, :members] if APP_CONFIG['anonymous_access']
  5. 1 before_action :load_platform, except: [:index, :allowed, :platforms_for_build, :create]
  6. 1 def allowed
  7. authorize :platform
  8. if request.authorization.present?
  9. token, pass = *ActionController::HttpAuthentication::Basic::user_name_and_password(request)
  10. end
  11. if Platform.allowed?(params[:path] || '', token)
  12. head :ok
  13. else
  14. head :forbidden
  15. end
  16. end
  17. 1 def index
  18. authorize :platform
  19. @platforms = PlatformPolicy::Scope.new(current_user, Platform).show.
  20. by_type(params[:type]).paginate(paginate_params)
  21. end
  22. 1 def show
  23. end
  24. 1 def projects
  25. render plain: @platform.projects.pluck(:owner_uname, :name).map { |p| "#{p[0]}/#{p[1]}" }.join("\n")
  26. end
  27. 1 def platforms_for_build
  28. authorize :platform
  29. @platforms = Platform.availables_main_platforms(current_user)
  30. render :index
  31. end
  32. 1 def create
  33. pp = params[:platform] || {}
  34. owner = User.find_by(id: pp[:owner_id])
  35. @platform = Platform.new(platform_params)
  36. @platform.owner = owner || get_owner
  37. create_subject @platform
  38. end
  39. 1 def update
  40. pp = params[:platform] || {}
  41. owner = User.find_by(id: pp[:owner_id])
  42. pp[:owner] = owner if owner
  43. update_subject @platform
  44. end
  45. 1 def members
  46. @members = @platform.members.order('name').paginate(paginate_params)
  47. end
  48. 1 def add_member
  49. add_member_to_subject @platform
  50. end
  51. 1 def remove_member
  52. remove_member_from_subject @platform
  53. end
  54. 1 def clone
  55. platform_params = params[:platform] || {}
  56. platform_params[:owner] = current_user
  57. @cloned = @platform.full_clone(platform_params)
  58. if @cloned.persisted?
  59. render_json_response @platform, 'Platform has been cloned successfully'
  60. else
  61. render_validation_error @platform, 'Platform has not been cloned'
  62. end
  63. end
  64. 1 def clear
  65. @platform.clear
  66. render_json_response @platform, 'Platform has been cleared successfully'
  67. end
  68. 1 def destroy
  69. destroy_subject @platform
  70. end
  71. 1 private
  72. 1 def platform_params
  73. subject_params(Platform)
  74. end
  75. # Private: before_action hook which loads Platform.
  76. 1 def load_platform
  77. authorize @platform = Platform.find(params[:id])
  78. end
  79. end

app/controllers/api/v1/product_build_lists_controller.rb

42.42% lines covered

33 relevant lines. 14 lines covered and 19 lines missed.
    
  1. 1 class Api::V1::ProductBuildListsController < Api::V1::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 skip_before_action :authenticate_user!, only: [:index, :show] if APP_CONFIG['anonymous_access']
  4. 1 before_action :load_product, only: :index
  5. 1 before_action :load_product_build_list, except: [:index, :create]
  6. 1 def index
  7. @product_build_lists =
  8. if @product
  9. @product.product_build_lists
  10. else
  11. PlatformPolicy::Scope.new(current_user, ProductBuildList.joins(product: :platform)).show
  12. end
  13. @product_build_lists = @product_build_lists.joins(:product, :project, :arch)
  14. @product_build_lists = @product_build_lists.recent.paginate(paginate_params)
  15. end
  16. 1 def create
  17. @product_build_list = ProductBuildList.new subject_params(ProductBuildList)
  18. @product_build_list.project ||= @product_build_list.try(:product).try(:project)
  19. @product_build_list.main_script ||= @product_build_list.try(:product).try(:main_script)
  20. @product_build_list.params ||= @product_build_list.try(:product).try(:params)
  21. @product_build_list.time_living ||= @product_build_list.try(:product).try(:time_living)
  22. create_subject @product_build_list
  23. end
  24. 1 def show
  25. end
  26. 1 def update
  27. params[:product_build_list] = {not_delete: (params[:product_build_list] || {})[:not_delete]}
  28. update_subject @product_build_list
  29. end
  30. 1 def destroy
  31. destroy_subject @product_build_list
  32. end
  33. 1 def cancel
  34. if @product_build_list.try(:can_cancel?) && @product_build_list.cancel
  35. render_json_response @product_build_list, t("layout.product_build_lists.cancel_success")
  36. else
  37. render_validation_error @product_build_list, t("layout.product_build_lists.cancel_fail")
  38. end
  39. end
  40. 1 private
  41. # Private: before_action hook which loads ProductBuildList.
  42. 1 def load_product_build_list
  43. authorize @product_build_list = ProductBuildList.find(params[:id])
  44. end
  45. # Private: before_action hook which loads Product.
  46. 1 def load_product
  47. authorize @product = Product.find(params[:product_id]), :show? if params[:product_id]
  48. end
  49. end

app/controllers/api/v1/products_controller.rb

71.43% lines covered

14 relevant lines. 10 lines covered and 4 lines missed.
    
  1. 1 class Api::V1::ProductsController < Api::V1::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 skip_before_action :authenticate_user!, only: [:index, :show] if APP_CONFIG['anonymous_access']
  4. 1 before_action :load_product, except: :create
  5. 1 def create
  6. create_subject @product = Product.new(subject_params(Product))
  7. end
  8. 1 def update
  9. update_subject @product
  10. end
  11. 1 def show
  12. end
  13. 1 def destroy
  14. destroy_subject @product
  15. end
  16. 1 private
  17. # Private: before_action hook which loads Product.
  18. 1 def load_product
  19. authorize @product = Product.find(params[:id])
  20. end
  21. end

app/controllers/api/v1/projects_controller.rb

41.3% lines covered

46 relevant lines. 19 lines covered and 27 lines missed.
    
  1. 1 class Api::V1::ProjectsController < Api::V1::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 skip_before_action :authenticate_user!, only: [:get_id, :show, :refs_list] if APP_CONFIG['anonymous_access']
  4. 1 before_action :load_project, except: [:index, :create, :get_id]
  5. 1 def index
  6. authorize :project
  7. @projects = ProjectPolicy::Scope.new(current_user, Project).
  8. membered.paginate(paginate_params)
  9. end
  10. 1 def get_id
  11. authorize @project = Project.find_by_owner_and_name!(params[:owner], params[:name])
  12. end
  13. 1 def show
  14. end
  15. 1 def refs_list
  16. @refs = @project.repo.branches + @project.repo.tags.select{ |t| t.commit }
  17. end
  18. 1 def update
  19. update_subject @project
  20. end
  21. 1 def destroy
  22. destroy_subject @project
  23. end
  24. 1 def create
  25. @project = Project.new subject_params(Project)
  26. p_params = params[:project] || {}
  27. owner_type = %w(User Group).find{ |t| t == p_params[:owner_type] }
  28. if owner_type.present?
  29. @project.owner = owner_type.constantize.find_by(id: p_params[:owner_id])
  30. else
  31. @project.owner = nil
  32. end
  33. authorize @project
  34. create_subject @project
  35. end
  36. 1 def members
  37. @members = @project.collaborators.order('uname').paginate(paginate_params)
  38. end
  39. 1 def add_member
  40. add_member_to_subject @project, params[:role]
  41. end
  42. 1 def remove_member
  43. remove_member_from_subject @project
  44. end
  45. 1 def update_member
  46. update_member_in_subject @project
  47. end
  48. 1 def fork(is_alias = false)
  49. owner = (Group.find params[:group_id] if params[:group_id].present?) || current_user
  50. authorize @project, :show?
  51. authorize owner, :write? if owner.is_a?(Group)
  52. if forked = @project.fork(owner, new_name: params[:fork_name], is_alias: is_alias) and forked.valid?
  53. render_json_response forked, 'Project has been forked successfully'
  54. else
  55. render_validation_error forked, 'Project has not been forked'
  56. end
  57. end
  58. 1 def alias
  59. authorize @project
  60. fork(true)
  61. end
  62. 1 private
  63. # Private: before_action hook which loads Project.
  64. 1 def load_project
  65. authorize @project = Project.find(params[:id])
  66. end
  67. end

app/controllers/api/v1/pull_requests_controller.rb

20.18% lines covered

109 relevant lines. 22 lines covered and 87 lines missed.
    
  1. 1 class Api::V1::PullRequestsController < Api::V1::BaseController
  2. 1 include Api::V1::Issueable
  3. 1 before_action :authenticate_user!
  4. 1 skip_before_action :authenticate_user!, only: %i(show index group_index commits files) if APP_CONFIG['anonymous_access']
  5. 1 before_action :load_group, only: %i(group_index)
  6. 1 before_action :load_project, except: %i(all_index user_index)
  7. 1 before_action :load_issue, only: %i(show index commits files merge update)
  8. 1 before_action :load_pull, only: %i(show index commits files merge update)
  9. 1 def index
  10. @pulls = @project.pull_requests
  11. @pulls_url = api_v1_project_pull_requests_path(@project, format: :json)
  12. render_pulls_list
  13. end
  14. 1 def all_index
  15. authorize :pull_request, :index?
  16. project_ids = get_all_project_ids membered_projects.pluck(:id)
  17. @pulls = PullRequest.where('pull_requests.to_project_id IN (?)', project_ids)
  18. @pulls_url = api_v1_pull_requests_path format: :json
  19. render_pulls_list
  20. end
  21. 1 def user_index
  22. authorize :pull_request, :index?
  23. project_ids = get_all_project_ids current_user.projects.pluck(:id)
  24. @pulls = PullRequest.where('pull_requests.to_project_id IN (?)', project_ids)
  25. @pulls_url = pull_requests_api_v1_user_path format: :json
  26. render_pulls_list
  27. end
  28. 1 def group_index
  29. project_ids = @group.projects.pluck(:id)
  30. project_ids = membered_projects.where(id: project_ids).pluck(:id)
  31. @pulls = PullRequest.where(to_project_id: project_ids)
  32. @pulls_url = pull_requests_api_v1_group_path
  33. render_pulls_list
  34. end
  35. 1 def show
  36. redirect_to api_v1_project_issue_path(@project.id, @issue.serial_id) and return if @pull.nil?
  37. end
  38. 1 def create
  39. from_project = Project.find_by(id: pull_params[:from_project_id])
  40. from_project ||= @project
  41. authorize from_project, :show?
  42. @pull = @project.pull_requests.build
  43. @pull.build_issue title: pull_params[:title], body: pull_params[:body]
  44. @pull.from_project = from_project
  45. @pull.to_ref, @pull.from_ref = pull_params[:to_ref], pull_params[:from_ref]
  46. @pull.issue.assignee_id = pull_params[:assignee_id] if policy(@project).write?
  47. @pull.issue.user, @pull.issue.project = current_user, @project
  48. @pull.issue.new_pull_request = true
  49. render_validation_error(@pull, "#{@pull.class.name} has not been created") && return unless @pull.valid?
  50. authorize @pull
  51. @pull.save # set pull id
  52. @pull.reload
  53. @pull.check(false) # don't make event transaction
  54. if @pull.already?
  55. @pull.destroy
  56. error_message = I18n.t('projects.pull_requests.up_to_date', to_ref: @pull.to_ref, from_ref: @pull.from_ref)
  57. render_json_response(@pull, error_message, 422)
  58. else
  59. @pull.send(@pull.status == 'blocked' ? 'block' : @pull.status)
  60. render_json_response @pull, "#{@pull.class.name} has been created successfully"
  61. end
  62. end
  63. 1 def update
  64. @pull = @project.pull_requests.includes(:issue).where(issues: {serial_id: params[:id]}).first
  65. authorize @pull
  66. if pull_params.present?
  67. attrs = subject_params(PullRequest)
  68. attrs.merge!(assignee_id: pull_params[:assignee_id]) if policy(@project).write?
  69. if action = %w(close reopen).find{ |s| s == pull_params[:status] }
  70. if @pull.send("can_#{action}?")
  71. @pull.set_user_and_time current_user
  72. need_check = true if action == 'reopen' && @pull.valid?
  73. end
  74. end
  75. end
  76. class_name = @pull.class.name
  77. if @pull.issue.update(attrs)
  78. @pull.send(action) if action.present?
  79. @pull.check if need_check
  80. render_json_response @pull, "#{class_name} has been updated successfully"
  81. else
  82. render_validation_error @pull, "#{class_name} has not been updated"
  83. end
  84. end
  85. 1 def commits
  86. authorize @pull
  87. @commits = @pull.repo.commits_between(@pull.to_commit, @pull.from_commit).paginate(paginate_params)
  88. end
  89. 1 def files
  90. authorize @pull
  91. @stats = @pull.diff_stats.zip(@pull.diff).paginate(paginate_params)
  92. end
  93. 1 def merge
  94. authorize @pull
  95. class_name = @pull.class.name
  96. if @pull.merge!(current_user)
  97. render_json_response @pull, "#{class_name} has been merged successfully"
  98. else
  99. render_validation_error @pull, "#{class_name} has not been merged"
  100. end
  101. end
  102. 1 private
  103. # Private: before_action hook which loads PullRequest.
  104. 1 def load_pull
  105. @pull = @issue.pull_request
  106. authorize @pull, :show? if @pull
  107. end
  108. 1 def render_pulls_list
  109. @pulls = @pulls.includes(issue: [:user, :assignee])
  110. if params[:status] == 'closed'
  111. @pulls = @pulls.closed_or_merged
  112. else
  113. @pulls = @pulls.not_closed_or_merged
  114. end
  115. if action_name == 'index' && params[:assignee].present?
  116. case params[:assignee]
  117. when 'none'
  118. @pulls = @pulls.where('issues.assigned_id IS NULL')
  119. when '*'
  120. @pulls = @pulls.where('issues.assigned_id IS NOT NULL')
  121. else
  122. @pulls = @pulls.where('assignees_issues.uname = ?', params[:assignee])
  123. end
  124. end
  125. if %w[all_index user_index group_index].include?(action_name)
  126. case params[:filter]
  127. when 'created'
  128. @pulls = @pulls.where('issues.user_id = ?', current_user.id)
  129. when 'all'
  130. else
  131. @pulls = @pulls.where('issues.assignee_id = ?', current_user.id)
  132. end
  133. else
  134. @pulls.where('users.uname = ?', params[:creator]) if params[:creator].present?
  135. end
  136. sort = params[:sort] == 'updated' ? 'issues.updated_at' : 'issues.created_at'
  137. direction = params[:direction] == 'asc' ? 'ASC' : 'DESC'
  138. @pulls = @pulls.order("#{sort} #{direction}")
  139. @pulls = @pulls.where('issues.created_at >= to_timestamp(?)', params[:since]) if params[:since] =~ /\A\d+\z/
  140. @pulls = @pulls.paginate(paginate_params)
  141. render :index
  142. end
  143. 1 def pull_params
  144. @pull_params ||= params[:pull_request] || {}
  145. end
  146. end

app/controllers/api/v1/repositories_controller.rb

31.34% lines covered

67 relevant lines. 21 lines covered and 46 lines missed.
    
  1. 1 class Api::V1::RepositoriesController < Api::V1::BaseController
  2. 1 respond_to :csv, only: :packages
  3. 1 before_action :authenticate_user!
  4. 1 skip_before_action :authenticate_user!, only: [:show, :projects] if APP_CONFIG['anonymous_access']
  5. 1 before_action :load_repository
  6. 1 def show
  7. end
  8. 1 def projects
  9. @projects = @repository.projects.recent.paginate(paginate_params)
  10. end
  11. 1 def update
  12. update_subject @repository
  13. end
  14. 1 def add_member
  15. add_member_to_subject @repository
  16. end
  17. 1 def remove_member
  18. remove_member_from_subject @repository
  19. end
  20. 1 def destroy
  21. destroy_subject @repository
  22. end
  23. 1 def public_key
  24. if @repository.key_pair
  25. render plain: @repository.key_pair.public.gsub("\r\n", "\n") + "\n"
  26. else
  27. render plain: ''
  28. end
  29. end
  30. 1 def key_pair
  31. end
  32. # Only one request per 15 minutes for each platform
  33. 1 def packages
  34. key, now = [@repository.platform.id, :repository_packages], Time.zone.now
  35. last_request = Rails.cache.read(key)
  36. if last_request.present? && last_request + 15.minutes > now
  37. raise Pundit::NotAuthorizedError
  38. else
  39. Rails.cache.write(key, now, expires_at: 15.minutes)
  40. respond_to do |format|
  41. format.csv do
  42. set_csv_file_headers :packages
  43. set_streaming_headers
  44. response.status = 200
  45. # setting the body to an enumerator, rails will iterate this enumerator
  46. self.response_body = Enumerator.new do |y|
  47. y << Api::V1::RepositoryPackagePresenter.csv_header.to_s
  48. BuildList::Package.by_repository(@repository) do |package|
  49. y << Api::V1::RepositoryPackagePresenter.new(package).to_csv_row.to_s
  50. end
  51. end
  52. end
  53. end
  54. end
  55. end
  56. 1 def add_repo_lock_file
  57. @repository.add_repo_lock_file
  58. render_json_response @repository, "'.repo.lock' file has been added to repository successfully"
  59. end
  60. 1 def remove_repo_lock_file
  61. @repository.remove_repo_lock_file
  62. render_json_response @repository, "'.repo.lock' file has been removed from repository successfully"
  63. end
  64. 1 def add_project
  65. if project = Project.where(id: params[:project_id]).first
  66. if policy(project).read?
  67. begin
  68. @repository.projects << project
  69. render_json_response @repository, "Project '#{project.id}' has been added to repository successfully"
  70. rescue ActiveRecord::RecordInvalid
  71. render_validation_error @repository, t('flash.repository.project_not_added')
  72. end
  73. else
  74. render_validation_error @repository, 'You have no access to read this project'
  75. end
  76. else
  77. render_validation_error @repository, "Project has not been added to repository"
  78. end
  79. end
  80. 1 def remove_project
  81. project_id = params[:project_id]
  82. ProjectToRepository.where(project_id: project_id, repository_id: @repository.id).destroy_all
  83. render_json_response @repository, "Project '#{project_id}' has been removed from repository successfully"
  84. end
  85. 1 def signatures
  86. key_pair = @repository.key_pair
  87. key_pair.destroy if key_pair
  88. key_pair = @repository.build_key_pair subject_params(Repository, KeyPair)
  89. key_pair.user_id = current_user.id
  90. authorize key_pair, :create?
  91. if key_pair.save
  92. render_json_response @repository, 'Signatures have been updated for repository successfully'
  93. else
  94. render_json_response @repository, error_message(key_pair, 'Signatures have not been updated for repository'), 422
  95. end
  96. end
  97. 1 private
  98. # Private: before_action hook which loads Repository.
  99. 1 def load_repository
  100. authorize @repository = Repository.find(params[:id])
  101. end
  102. end

app/controllers/api/v1/search_controller.rb

25.0% lines covered

8 relevant lines. 2 lines covered and 6 lines missed.
    
  1. 1 class Api::V1::SearchController < Api::V1::BaseController
  2. 1 def index
  3. authorize :search
  4. search = Search.new(params[:query], current_user, paginate_params)
  5. types = Search::TYPES.find{ |t| t == params[:type] } || Search::TYPES
  6. @results = {}
  7. [types].flatten.each do |type|
  8. @results[type] = search.send(type)
  9. end
  10. end
  11. end

app/controllers/api/v1/users_controller.rb

41.18% lines covered

34 relevant lines. 14 lines covered and 20 lines missed.
    
  1. 1 class Api::V1::UsersController < Api::V1::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 skip_before_action :authenticate_user!, only: [:show] if APP_CONFIG['anonymous_access']
  4. 1 before_action :load_user, only: %i(show)
  5. 1 before_action :set_current_user, except: :show
  6. 1 def show
  7. @user = User.opened.find params[:id] # dont show system users
  8. end
  9. 1 def show_current_user
  10. render :show
  11. end
  12. 1 def update
  13. user_params = params[:user] || {}
  14. send_confirmation = if user_params.include?(:email) && user_params[:email] != @user.email
  15. true
  16. else
  17. false
  18. end
  19. if @user.update_without_password(subject_params(User))
  20. if send_confirmation
  21. @user.confirmed_at, @user.confirmation_sent_at = nil
  22. @user.send_confirmation_instructions
  23. end
  24. render_json_response @user, 'User has been updated successfully'
  25. else
  26. render_validation_error @user, "#{class_name} has not been updated"
  27. end
  28. end
  29. 1 def notifiers
  30. if request.put?
  31. if @user.notifier.update(notifier_params)
  32. render_json_response @user, 'User notification settings have been updated successfully'
  33. else
  34. render_json_response @user, error_message(@user.notifier, 'User notification settings have not been updated'), 422
  35. end
  36. end
  37. end
  38. 1 def tokens
  39. render plain: User.pluck(:authentication_token).join("\n")
  40. end
  41. 1 protected
  42. 1 def notifier_params
  43. permit_params(:notifiers, *policy(SettingsNotifier).permitted_attributes)
  44. end
  45. 1 def set_current_user
  46. authorize @user = current_user
  47. end
  48. # Private: before_action hook which loads User.
  49. 1 def load_user
  50. authorize @user = User.find(params[:id])
  51. end
  52. end

app/controllers/application_controller.rb

63.41% lines covered

82 relevant lines. 52 lines covered and 30 lines missed.
    
  1. 1 class ApplicationController < ActionController::Base
  2. 1 include StrongParams
  3. 1 include Pundit
  4. SENTRY_IGNORE = [
  5. 1 ActionController::InvalidAuthenticityToken,
  6. AbstractController::ActionNotFound
  7. ]
  8. 1 protect_from_forgery
  9. 1 layout :layout_by_resource
  10. # Hack to prevent token auth on all pages except atom feed:
  11. 4 prepend_before_action -> { redirect_to(new_user_session_path) if params[:token] && params[:token].is_a?(String) && params[:format] != 'atom'}
  12. 1 before_action :set_locale
  13. 1 before_action -> { EventLog.current_controller = self },
  14. only: [:create, :destroy, :open_id, :cancel, :publish, :change_visibility] # :update
  15. 1 before_action :banned?
  16. 4 after_action -> { EventLog.current_controller = nil }
  17. 1 after_action :verify_authorized, unless: :devise_controller?
  18. 1 skip_after_action :verify_authorized, only: %i(render_500 render_404)
  19. 1 before_action :set_raven_context
  20. 1 helper_method :get_owner
  21. 1 unless Rails.env.development?
  22. 1 rescue_from Exception, with: :render_500
  23. 1 rescue_from ActiveRecord::RecordNotFound,
  24. # ActionController::RoutingError, # see: config/routes.rb:<last line>
  25. # ActionController::UnknownController,
  26. ActionController::UnknownFormat,
  27. AbstractController::ActionNotFound, with: :render_404
  28. end
  29. 1 rescue_from Pundit::NotAuthorizedError do |exception|
  30. redirect_to forbidden_url, alert: t("flash.exception_message")
  31. end
  32. 1 rescue_from Grit::NoSuchPathError, with: :not_found
  33. 1 def render_404
  34. render_error 404
  35. end
  36. 1 protected
  37. # Disables access to site for banned users
  38. 1 def banned?
  39. 3 if user_signed_in? && current_user.access_locked?
  40. sign_out current_user
  41. flash[:error] = I18n.t('devise.failure.locked')
  42. redirect_to root_path
  43. end
  44. end
  45. 1 def authenticate_admin!
  46. authenticate_user!
  47. redirect_to root_url unless current_user.admin?
  48. end
  49. # For this example, we are simply using token authentication
  50. # via parameters. However, anyone could use Rails's token
  51. # authentication features to get the token from a header.
  52. 1 def authenticate_user!
  53. 3 if user = find_user_by_token
  54. # Notice we are passing store false, so the user is not
  55. # actually stored in the session and a token is needed
  56. # for every request. If you want the token to work as a
  57. # sign in token, you can simply remove store: false.
  58. sign_in user, store: false
  59. else
  60. 3 super
  61. end
  62. end
  63. 1 def authenticate_user
  64. 3 if user = find_user_by_token
  65. sign_in user, store: false
  66. end
  67. end
  68. 1 def find_user_by_token
  69. 6 user_token = params[:authentication_token].presence
  70. 6 if user_token.blank? && request.authorization.present?
  71. token, pass = *ActionController::HttpAuthentication::Basic::user_name_and_password(request)
  72. user_token = token if pass.blank?
  73. end
  74. 6 user = user_token && User.find_by_authentication_token(user_token.to_s)
  75. end
  76. 1 def render_500(e)
  77. #check for exceptions Sentry ignores by default and exclude them from manual Sentry notification
  78. if Rails.env.production? && !SENTRY_IGNORE.include?(e.class)
  79. Raven.capture_exception(e)
  80. end
  81. Rails.logger.error e.backtrace.inspect
  82. Rails.logger.error e.message
  83. render_error 500
  84. end
  85. 1 def render_error(status)
  86. respond_to do |format|
  87. format.json { render json: {status: status, message: t("flash.#{status}_message")}.to_json, status: status }
  88. format.all { render file: Rails.root.join("public/#{status}.html"), status: status,
  89. alert: t("flash.#{status}_message"), layout: false, content_type: 'text/html' }
  90. end
  91. end
  92. # Helper method for all controllers
  93. 1 def permit_params(param_name, *accessible)
  94. (params[param_name] || ActionController::Parameters.new).permit(*accessible.flatten).to_h
  95. end
  96. 1 def set_locale
  97. 3 I18n.locale = check_locale( get_user_locale ||
  98. (request.env['HTTP_ACCEPT_LANGUAGE'] ? request.env['HTTP_ACCEPT_LANGUAGE'][0,2].downcase : nil ))
  99. end
  100. 1 def get_user_locale
  101. 3 user_signed_in? ? current_user.language : nil
  102. end
  103. 1 def check_locale(locale)
  104. 3 User::LANGUAGES.include?(locale.to_s) ? locale : :en
  105. end
  106. 1 def get_owner
  107. if self.class.method_defined? :parent
  108. if parent and (parent.is_a? User or parent.is_a? Group)
  109. return parent
  110. else
  111. return current_user
  112. end
  113. else
  114. params['user_id'] && User.find(params['user_id']) ||
  115. params['group_id'] && Group.find(params['group_id']) || current_user
  116. end
  117. end
  118. 1 def layout_by_resource
  119. 1 if devise_controller?
  120. "sessions"
  121. else
  122. 1 "application"
  123. end
  124. end
  125. 1 def not_found
  126. raise ActionController::RoutingError.new('Not Found')
  127. end
  128. 1 def current_page
  129. params[:page] = 1 if params[:page].to_i < 1
  130. params[:page]
  131. end
  132. 1 def set_raven_context
  133. 3 Raven.user_context(email: current_user.try(:email), id: current_user.try(:id))
  134. 3 Raven.extra_context(params: params.to_unsafe_h, url: request.url)
  135. end
  136. end

app/controllers/autocompletes_controller.rb

37.93% lines covered

29 relevant lines. 11 lines covered and 18 lines missed.
    
  1. 1 class AutocompletesController < ApplicationController
  2. 1 before_action :authenticate_user!
  3. 1 skip_after_action :verify_authorized
  4. 1 def autocomplete_user_uname
  5. results = User.opened.search_like(params[:query]).search_order.limit(5)
  6. render json: results.map{ |u| { id: u.id, name: u.uname } }
  7. end
  8. 1 def autocomplete_user_or_group
  9. results << User.opened.search_like(params[:query]).search_order.limit(5).pluck(:uname)
  10. results << Group.search_like(params[:query]).search_order.limit(5).pluck(:uname)
  11. render json: results.flatten.sort.map{ |r| { id: r, name: r } }
  12. end
  13. 1 def autocomplete_extra_build_list
  14. bl = BuildListPolicy::Scope.new(current_user, BuildList).read.
  15. for_extra_build_lists(params[:term], save_to_platform).first
  16. results << { :id => bl.id,
  17. :value => bl.id,
  18. :label => "#{bl.id} (#{bl.project.name} - #{bl.arch.name})",
  19. :path => build_list_path(bl)
  20. } if bl
  21. render json: results.to_json
  22. end
  23. 1 def autocomplete_extra_mass_build
  24. mb = MassBuild.where(id: params[:term]).first
  25. results << {
  26. id: mb.id,
  27. value: mb.id,
  28. label: "#{mb.id} - #{mb.name}",
  29. path: platform_mass_build_path(mb.save_to_platform, mb)
  30. } if mb && policy(mb).show?
  31. render json: results.to_json
  32. end
  33. 1 def autocomplete_extra_repositories
  34. # Only personal and build for platform repositories can be attached to the build
  35. platforms = PlatformPolicy::Scope.new(current_user, Platform).show.
  36. includes(:repositories).search_like(params[:term]).search_order.limit(5).
  37. where("platforms.platform_type = 'personal' OR platforms.id = ?", params[:build_for_platform_id])
  38. platforms.each do |platform|
  39. platform.repositories.each do |repository|
  40. results <<
  41. {
  42. id: repository.id,
  43. platform_name: platform.name,
  44. repository_name: repository.name,
  45. label: "#{platform.name}/#{repository.name}",
  46. path: platform_repository_path(platform, repository)
  47. }
  48. end
  49. end if save_to_platform.personal?
  50. render json: results.to_json
  51. end
  52. 1 protected
  53. 1 def save_to_platform
  54. @save_to_platform ||= Platform.find_cached(params[:platform_id])
  55. end
  56. 1 def results
  57. @results ||= []
  58. end
  59. end

app/controllers/concerns/api/v1/issueable.rb

55.56% lines covered

18 relevant lines. 10 lines covered and 8 lines missed.
    
  1. 1 module Api
  2. 1 module V1
  3. 1 module Issueable
  4. 1 extend ActiveSupport::Concern
  5. 1 protected
  6. # Private: before_action hook which loads Group.
  7. 1 def load_group
  8. authorize @group = Group.find(params[:id]), :show?
  9. end
  10. # Private: before_action hook which loads Project.
  11. 1 def load_project
  12. authorize @project = Project.find(params[:project_id]), :show?
  13. end
  14. # Private: before_action hook which loads Issue.
  15. 1 def load_issue
  16. authorize @issue = @project.issues.find_by!(serial_id: params[:id]), :show?
  17. end
  18. # Private: Get membered projects.
  19. #
  20. # Returns the ActiveRecord::Relation instance.
  21. 1 def membered_projects
  22. @membered_projects ||= ProjectPolicy::Scope.new(current_user, Project).membered
  23. end
  24. # Private: Get project ids which available for current user.
  25. #
  26. # Returns the Array of project ids.
  27. 1 def get_all_project_ids(default_project_ids)
  28. project_ids = []
  29. if %w(created all).include? params[:filter]
  30. # add own issues
  31. project_ids = Project.opened.joins(:issues).
  32. where(issues: {user_id: current_user.id}).
  33. pluck('projects.id')
  34. end
  35. project_ids | default_project_ids
  36. end
  37. end
  38. end
  39. end

app/controllers/concerns/strong_params.rb

62.5% lines covered

8 relevant lines. 5 lines covered and 3 lines missed.
    
  1. 1 module StrongParams
  2. 1 extend ActiveSupport::Concern
  3. 1 protected
  4. 1 def permit_params(param_name, *accessible)
  5. [param_name].flatten.inject(params.dup) do |pp, name|
  6. pp = pp[name] || ActionController::Parameters.new
  7. end.permit(*accessible.flatten)
  8. end
  9. 1 def subject_params(subject_class, subject = nil)
  10. permit_params(subject_class.name.underscore.to_sym, *policy(subject || subject_class).permitted_attributes)
  11. end
  12. end

app/controllers/groups/base_controller.rb

71.43% lines covered

7 relevant lines. 5 lines covered and 2 lines missed.
    
  1. 1 class Groups::BaseController < ApplicationController
  2. 1 before_action :authenticate_user!
  3. 1 before_action :find_group
  4. 1 protected
  5. # Private: before_action hook which loads Group.
  6. 1 def find_group
  7. if group_id = params[:uname] || params[:group_id] || params[:id]
  8. @group = Group.find_by_insensitive_uname! group_id
  9. end
  10. end
  11. end

app/controllers/groups/members_controller.rb

25.0% lines covered

24 relevant lines. 6 lines covered and 18 lines missed.
    
  1. 1 class Groups::MembersController < Groups::BaseController
  2. 1 before_action -> { authorize @group, :manage_members? }
  3. 1 def index
  4. @members = @group.members.order(:uname) - [@group.owner]
  5. end
  6. 1 def update
  7. raise Pundit::NotAuthorizedError if @group.owner_id.to_s == params[:member_id]
  8. relation = @group.actors.where(actor_id: params[:member_id], actor_type: 'User').first
  9. relation ||= @group.actors.build(actor_id: params[:member_id], actor_type: 'User')
  10. relation.role = params[:role]
  11. relation.save!
  12. flash[:notice] = t("flash.members.successfully_changed")
  13. redirect_to group_members_path(@group)
  14. end
  15. 1 def remove
  16. User.where(id: params[:members]).each do |user|
  17. @group.remove_member(user)
  18. end
  19. redirect_to group_members_path(@group)
  20. end
  21. 1 def add
  22. @user = User.find_by(id: params[:member_id])
  23. if !@user
  24. flash[:error] = t("flash.collaborators.wrong_user", uname: params[:user_uname])
  25. elsif @group.add_member(@user, params[:role])
  26. flash[:notice] = t("flash.members.successfully_added")
  27. else
  28. flash[:error] = t("flash.members.error_in_adding")
  29. end
  30. redirect_to group_members_path(@group)
  31. end
  32. end

app/controllers/groups/profile_controller.rb

25.42% lines covered

59 relevant lines. 15 lines covered and 44 lines missed.
    
  1. 1 class Groups::ProfileController < Groups::BaseController
  2. 1 include AvatarHelper
  3. 1 include PaginateHelper
  4. 1 skip_before_action :authenticate_user!, only: :show if APP_CONFIG['anonymous_access']
  5. 1 def index
  6. authorize :group
  7. @groups = current_user.groups.paginate(page: params[:group_page]) # accessible_by(current_ability)
  8. @groups = @groups.search_like(params[:query]) if params[:query].present?
  9. end
  10. 1 def show
  11. authorize @group
  12. respond_to do |format|
  13. format.html do
  14. @members = @group.members.order(:uname)
  15. end
  16. format.json do
  17. @projects = @group.own_projects.search_like(params[:term]).recent
  18. case params[:visibility]
  19. when 'open'
  20. @projects = @projects.opened
  21. when 'hidden'
  22. @projects = @projects.by_visibilities('hidden')
  23. @projects = @projects.none unless policy(@group).reader?
  24. else
  25. @projects = @projects.opened unless policy(@group).reader?
  26. end
  27. @total_items = @projects.count
  28. @projects = @projects.paginate(paginate_params)
  29. render 'users/profile/show'
  30. end
  31. end
  32. end
  33. 1 def new
  34. authorize @group = current_user.own_groups.build
  35. end
  36. 1 def edit
  37. authorize @group
  38. end
  39. 1 def create
  40. @group = current_user.own_groups.new
  41. @group.assign_attributes(group_params)
  42. authorize @group
  43. if @group.save
  44. flash[:notice] = t('flash.group.saved')
  45. redirect_to group_path(@group)
  46. else
  47. flash[:error] = t('flash.group.save_error')
  48. flash[:warning] = @group.errors.map(&:full_message).join('. ')
  49. render action: :new
  50. end
  51. end
  52. 1 def update
  53. authorize @group
  54. if @group.update(group_params)
  55. update_avatar(@group, params)
  56. flash[:notice] = t('flash.group.saved')
  57. redirect_to group_path(@group)
  58. else
  59. flash[:error] = t('flash.group.save_error')
  60. render action: :edit
  61. end
  62. end
  63. 1 def destroy
  64. authorize @group
  65. @group.destroy
  66. flash[:notice] = t("flash.group.destroyed")
  67. redirect_to groups_path
  68. end
  69. 1 def remove_user
  70. authorize @group
  71. Relation.by_actor(current_user).by_target(@group).destroy_all
  72. redirect_to groups_path
  73. end
  74. 1 protected
  75. 1 def group_params
  76. subject_params(Group, @group)
  77. end
  78. 1 def paginate_projects(page)
  79. @projects.paginate(page: (page>0 ? page : nil), per_page: 24)
  80. end
  81. end

app/controllers/home_controller.rb

16.67% lines covered

60 relevant lines. 10 lines covered and 50 lines missed.
    
  1. 1 class HomeController < ApplicationController
  2. 1 before_action :authenticate_user!, except: [:root]
  3. 1 skip_after_action :verify_authorized
  4. 1 def root
  5. respond_to do |format|
  6. format.html { render 'pages/tour/abf-tour-project-description-1' }
  7. end
  8. end
  9. 1 def activity(is_my_activity = false)
  10. @filter = t('feed_menu').has_key?(params[:filter].try(:to_sym)) ? params[:filter].to_sym : :all
  11. @activity_feeds = current_user.activity_feeds
  12. .by_project_name(params[:project_name_filter])
  13. .by_owner_uname(params[:owner_filter])
  14. @activity_feeds = @activity_feeds.where(kind: "ActivityFeed::#{@filter.upcase}".constantize) unless @filter == :all
  15. @activity_feeds = @activity_feeds.where(user_id: current_user) if @own_filter == :created
  16. @activity_feeds = @activity_feeds.where.not(user_id: current_user) if @own_filter == :not_created
  17. @activity_feeds = if is_my_activity
  18. @activity_feeds.where(creator_id: current_user)
  19. else
  20. @activity_feeds.where.not(creator_id: current_user)
  21. end
  22. @activity_feeds = @activity_feeds.paginate page: current_page
  23. respond_to do |format|
  24. format.html { render 'activity' }
  25. format.json { render 'activity' }
  26. format.atom
  27. end
  28. end
  29. 1 def own_activity
  30. activity(true)
  31. end
  32. 1 def issues
  33. @created_issues = current_user.issues
  34. @assigned_issues = Issue.where(assignee_id: current_user.id)
  35. @all_issues = ProjectPolicy::Scope.new(current_user, Issue).membered.distinct.joins(:project)
  36. @created_issues, @assigned_issues, @all_issues =
  37. if action_name == 'issues'
  38. [@created_issues.without_pull_requests,
  39. @assigned_issues.without_pull_requests,
  40. @all_issues.without_pull_requests]
  41. else
  42. [@created_issues.joins(:pull_request),
  43. @assigned_issues.joins(:pull_request),
  44. @all_issues.joins(:pull_request)]
  45. end
  46. case params[:filter]
  47. when 'created'
  48. @issues = @created_issues
  49. when 'assigned'
  50. @issues = @assigned_issues
  51. else
  52. params[:filter] = 'all' # default
  53. @issues = @all_issues
  54. end
  55. @filter = params[:filter]
  56. @opened_issues, @closed_issues = @issues.not_closed_or_merged, @issues.closed_or_merged
  57. @status = params[:status] == 'closed' ? :closed : :open
  58. @issues = @issues.send( (@status == :closed) ? :closed_or_merged : :not_closed_or_merged )
  59. @sort = params[:sort] == 'updated' ? :updated : :created
  60. @direction = params[:direction] == 'asc' ? :asc : :desc
  61. @issues = @issues.order("issues.#{@sort}_at #{@direction}")
  62. .includes(:assignee, :user, :pull_request).distinct
  63. .paginate page: current_page
  64. respond_to do |format|
  65. format.html { render 'activity' }
  66. format.json { render 'issues' }
  67. end
  68. end
  69. 1 def pull_requests
  70. issues
  71. end
  72. 1 def get_owners_list
  73. if params[:term].present?
  74. users = User.opened.search_like(params[:term]).first(5)
  75. groups = Group.opened.search_like(params[:term]).first(5)
  76. @owners = users | groups
  77. end
  78. respond_to do |format|
  79. format.json {}
  80. end
  81. end
  82. 1 def get_project_names_list
  83. if params[:term].present?
  84. @projects = ProjectPolicy::Scope.new(current_user, Project).membered
  85. @projects = @projects.where(owner_uname: params[:owner_uname]) if params[:owner_uname].present?
  86. @projects = @projects.by_name("%#{params[:term]}%")
  87. .distinct
  88. .pluck(:name)
  89. .first(10)
  90. end
  91. respond_to do |format|
  92. format.json {}
  93. end
  94. end
  95. end

app/controllers/pages_controller.rb

50.0% lines covered

10 relevant lines. 5 lines covered and 5 lines missed.
    
  1. 1 class PagesController < ApplicationController
  2. 1 skip_after_action :verify_authorized
  3. 1 def tour_inside
  4. @entries = case params[:id]
  5. when 'builds'
  6. %w(repo builds monitoring)
  7. when 'sources'
  8. %w(source history annotation edit)
  9. when 'projects'
  10. %w(control git tracker)
  11. end
  12. render "pages/tour/tour-inside"
  13. end
  14. 1 def forbidden
  15. end
  16. 1 def tos
  17. end
  18. end

app/controllers/platforms/base_controller.rb

66.67% lines covered

6 relevant lines. 4 lines covered and 2 lines missed.
    
  1. 1 class Platforms::BaseController < ApplicationController
  2. 1 before_action :load_platform
  3. 1 protected
  4. 1 def load_platform
  5. return unless params[:platform_id]
  6. authorize @platform = Platform.find_cached(params[:platform_id]), :show?
  7. end
  8. end

app/controllers/platforms/contents_controller.rb

35.29% lines covered

17 relevant lines. 6 lines covered and 11 lines missed.
    
  1. 1 class Platforms::ContentsController < Platforms::BaseController
  2. 1 include PaginateHelper
  3. 1 before_action :authenticate_user!
  4. 1 skip_before_action :authenticate_user!, only: :index if APP_CONFIG['anonymous_access']
  5. 1 def index
  6. respond_to do |format|
  7. format.html
  8. format.json do
  9. @path = params[:path].to_s
  10. @term = params[:term]
  11. @contents = PlatformContent.find_by_platform(@platform, @path, @term)
  12. @total_items = @contents.count
  13. @contents = @contents.paginate(paginate_params)
  14. end
  15. end
  16. end
  17. 1 def remove_file
  18. authorize @platform
  19. PlatformContent.remove_file(@platform, params[:path])
  20. head :ok
  21. end
  22. end

app/controllers/platforms/key_pairs_controller.rb

26.32% lines covered

19 relevant lines. 5 lines covered and 14 lines missed.
    
  1. 1 class Platforms::KeyPairsController < Platforms::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 def index
  4. @key_pair = KeyPair.new
  5. end
  6. 1 def create
  7. @key_pair = KeyPair.new subject_params(KeyPair)
  8. @key_pair.user_id = current_user.id
  9. authorize @key_pair
  10. if @key_pair.save
  11. flash[:notice] = t('flash.key_pairs.saved')
  12. redirect_to platform_key_pairs_path(@key_pair.repository.platform) and return
  13. else
  14. flash[:error] = t('flash.key_pairs.save_error')
  15. end
  16. render :index
  17. end
  18. 1 def destroy
  19. authorize @key_pair = @platform.key_pairs.find(params[:id])
  20. if @key_pair.destroy
  21. flash[:notice] = t('flash.key_pairs.destroyed')
  22. else
  23. flash[:error] = t('flash.key_pairs.destroy_error')
  24. end
  25. redirect_to platform_key_pairs_path(@key_pair.repository.platform)
  26. end
  27. end

app/controllers/platforms/maintainers_controller.rb

50.0% lines covered

10 relevant lines. 5 lines covered and 5 lines missed.
    
  1. 1 class Platforms::MaintainersController < Platforms::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 skip_before_action :authenticate_user!, only: [:index] if APP_CONFIG['anonymous_access']
  4. 1 def index
  5. @maintainer = BuildList::Package.new(build_list_package_params)
  6. @packages = @platform.packages.actual.like_name(@maintainer.name)
  7. @projects = @platform.projects.joins(:packages).merge( @packages ).
  8. includes(:maintainer).group('projects.id').reorder(:name).paginate(page: params[:page])
  9. @packages = @packages.where(project_id: @projects.map(&:id)).group_by(&:project_id)
  10. end
  11. 1 def build_list_package_params
  12. permit_params :build_list_package, :name
  13. end
  14. end

app/controllers/platforms/mass_builds_controller.rb

19.74% lines covered

76 relevant lines. 15 lines covered and 61 lines missed.
    
  1. 1 class Platforms::MassBuildsController < Platforms::BaseController
  2. 1 include DatatableHelper
  3. 1 before_action :authenticate_user!
  4. 1 skip_before_action :authenticate_user!, only: [:index, :get_list] if APP_CONFIG['anonymous_access']
  5. 1 before_action :find_mass_build, only: %i(show publish cancel get_list show_fail_reason)
  6. 1 def new
  7. if params[:mass_build_id].present?
  8. @mass_build = @platform.mass_builds.find(params[:mass_build_id]).dup
  9. @mass_build.arches = Arch.where(name: @mass_build.arch_names.split(', ')).pluck(:id)
  10. end
  11. authorize @mass_build ||= @platform.mass_builds.build
  12. @mass_build.arches ||= @platform.platform_arch_settings.by_default.pluck(:arch_id)
  13. @mass_build.repositories ||= []
  14. @mass_build.arches.map!(&:to_s)
  15. end
  16. 1 def show
  17. authorize @platform.mass_builds.find(params[:id])
  18. end
  19. 1 def create
  20. @mass_build = @platform.mass_builds.build(subject_params(MassBuild))
  21. @mass_build.user = current_user
  22. @mass_build.arches = params[:arches] || []
  23. @mass_build.repositories ||= params[:repositories] || []
  24. authorize @mass_build
  25. if @mass_build.save
  26. redirect_to(platform_mass_builds_path(@platform), notice: t("flash.platform.build_all_success"))
  27. else
  28. flash[:warning] = @mass_build.errors.map(&:full_message).join('. ')
  29. flash[:error] = t('flash.platform.build_all_error')
  30. render action: :new
  31. end
  32. end
  33. 1 def publish
  34. if params[:status] == 'test_failed'
  35. @mass_build.publish_test_failed_builds current_user
  36. else
  37. @mass_build.publish_success_builds current_user
  38. end
  39. redirect_to(platform_mass_builds_path(@mass_build.save_to_platform), notice: t("flash.platform.publish_success"))
  40. end
  41. 1 def index
  42. @mass_build = MassBuild.new(params[:mass_build])
  43. @mass_builds = @platform.mass_builds.search_like(@mass_build.description).
  44. order(id: :desc).paginate(page: params[:page])
  45. end
  46. 1 def cancel
  47. @mass_build.cancel_all
  48. flash[:notice] = t("flash.platform.cancel_mass_build")
  49. redirect_to platform_mass_builds_path(@mass_build.save_to_platform)
  50. end
  51. 1 def get_list
  52. text =
  53. case params[:kind]
  54. when 'failed_builds_list', 'tests_failed_builds_list', 'success_builds_list'
  55. @mass_build.send "generate_#{params[:kind]}"
  56. when 'projects_list', 'missed_projects_list'
  57. @mass_build.send params[:kind]
  58. end
  59. render plain: text
  60. end
  61. 1 def show_fail_reason
  62. respond_to do |format|
  63. format.html {
  64. @build_lists = @mass_build.build_lists.where(status: BuildList::BUILD_ERROR).page(params[:page])
  65. data = @build_lists.pluck(:id, :project_id, :arch_id, :fail_reason)
  66. arches = {}
  67. Arch.all.map do |arch|
  68. arches[arch.id] = arch.name
  69. end
  70. projects = {}
  71. @items = data.map do |item|
  72. if projects[item[1]]
  73. item[1] = projects[item[1]]
  74. else
  75. project_name_with_owner = Project.find(item[1]).name_with_owner
  76. projects[item[1]] = project_name_with_owner
  77. item[1] = project_name_with_owner
  78. end
  79. item[2] = arches[item[2]]
  80. item
  81. end
  82. }
  83. format.csv {
  84. log_name = params[:csv][:log_name].presence || 'script_output.log'
  85. headers.delete("Content-Length")
  86. headers["Cache-Control"] = "no-cache"
  87. headers["Content-Type"] = "text/csv"
  88. headers["Content-Disposition"] = "attachment; filename=\"mass_build_#{@mass_build.id}_failures.csv\""
  89. headers["X-Accel-Buffering"] = "no"
  90. self.response_body = Enumerator.new do |y|
  91. @mass_build.build_lists.includes(:project, :arch).find_each.lazy.each do |bl|
  92. log = bl.results.select { |x| x['file_name'] == log_name }.last
  93. line = CSV.generate_line([
  94. bl.id,
  95. BuildList::HUMAN_STATUSES[bl.status].to_s,
  96. bl.project.name_with_owner,
  97. bl.arch.name,
  98. bl.fail_reason.presence || 'Empty',
  99. log.present? ? "http://file-store.rosalinux.ru/api/v1/file_stores/#{log['sha1']}.log?show=true" : ''
  100. ], col_sep: ';;')
  101. y << line
  102. end
  103. end
  104. }
  105. end
  106. end
  107. 1 private
  108. # Private: before_action hook which loads MassBuild.
  109. 1 def find_mass_build
  110. authorize @mass_build = @platform.mass_builds.find(params[:id])
  111. end
  112. end

app/controllers/platforms/platforms_controller.rb

20.91% lines covered

110 relevant lines. 23 lines covered and 87 lines missed.
    
  1. 1 class Platforms::PlatformsController < Platforms::BaseController
  2. 1 include FileStoreHelper
  3. 1 before_action :authenticate_user!
  4. 1 skip_before_action :authenticate_user!, only: [:advisories, :members, :show] if APP_CONFIG['anonymous_access']
  5. 1 def index
  6. authorize :platform
  7. respond_to do |format|
  8. format.html {}
  9. format.json {
  10. @platforms = PlatformPolicy::Scope.new(current_user, Platform).related
  11. @platforms_count = @platforms.count
  12. @platforms = @platforms.paginate(page: current_page, per_page: Platform.per_page)
  13. }
  14. end
  15. end
  16. 1 def show
  17. end
  18. 1 def new
  19. authorize @platform = Platform.new
  20. @admin_uname = current_user.uname
  21. @admin_id = current_user.id
  22. end
  23. 1 def edit
  24. authorize @platform
  25. @admin_id = @platform.owner.id
  26. @admin_uname = @platform.owner.uname
  27. end
  28. 1 def create
  29. authorize @platform = Platform.new(platform_params)
  30. @admin_id = params[:admin_id]
  31. @admin_uname = params[:admin_uname]
  32. # FIXME: do not allow manipulate owner model, only platforms onwer_id and onwer_type
  33. @platform.owner = @admin_id.blank? ? get_owner : User.find(@admin_id)
  34. if @platform.save
  35. flash[:notice] = I18n.t("flash.platform.created")
  36. redirect_to @platform
  37. else
  38. flash[:error] = I18n.t("flash.platform.create_error")
  39. render action: :new
  40. end
  41. end
  42. 1 def update
  43. authorize @platform
  44. @admin_id = params[:admin_id]
  45. @admin_uname = params[:admin_uname]
  46. pp = platform_params
  47. pp[:owner] = User.find(@admin_id) if @admin_id.present?
  48. respond_to do |format|
  49. format.html do
  50. if @platform.update(pp)
  51. flash[:notice] = I18n.t("flash.platform.saved")
  52. redirect_to @platform
  53. else
  54. flash[:error] = I18n.t("flash.platform.save_error")
  55. render action: :edit
  56. end
  57. end
  58. format.json do
  59. if @platform.update(pp)
  60. render json: { notice: I18n.t("flash.platform.saved") }.to_json
  61. else
  62. render json: { error: I18n.t("flash.platform.save_error") }.to_json, status: 422
  63. end
  64. end
  65. end
  66. end
  67. 1 def regenerate_metadata
  68. authorize @platform
  69. if @platform.regenerate
  70. flash[:notice] = I18n.t('flash.platform.saved')
  71. else
  72. flash[:error] = I18n.t('flash.platform.save_error')
  73. end
  74. redirect_to edit_platform_path(@platform)
  75. end
  76. 1 def change_visibility
  77. authorize @platform
  78. if @platform.change_visibility
  79. flash[:notice] = I18n.t("flash.platform.saved")
  80. redirect_to @platform
  81. else
  82. flash[:error] = I18n.t("flash.platform.save_error")
  83. flash[:warning] = @platform.errors.map(&:full_message).join('. ')
  84. render action: :edit
  85. end
  86. end
  87. 1 def clone
  88. authorize @platform
  89. @cloned = Platform.new
  90. @cloned.name = @platform.name + "_clone"
  91. @cloned.description = @platform.description + "_clone"
  92. end
  93. 1 def make_clone
  94. authorize @platform
  95. @cloned = @platform.full_clone platform_params.merge(owner: current_user)
  96. if @cloned.persisted?
  97. flash[:notice] = I18n.t("flash.platform.clone_success")
  98. redirect_to @cloned
  99. else
  100. flash[:error] = @cloned.errors.map(&:full_message).join('. ')
  101. render 'clone'
  102. end
  103. end
  104. 1 def destroy
  105. authorize @platform
  106. @platform.destroy # later with resque
  107. flash[:notice] = t("flash.platform.destroyed")
  108. redirect_to platforms_path
  109. end
  110. 1 def members
  111. authorize @platform
  112. @members = @platform.members.order(:uname)
  113. end
  114. 1 def remove_members
  115. authorize @platform
  116. User.where(id: params[:members]).each do |user|
  117. @platform.remove_member(user)
  118. end
  119. redirect_to members_platform_path(@platform)
  120. end
  121. 1 def add_member
  122. authorize @platform
  123. member = User.find_by(id: params[:member_id])
  124. if !member
  125. flash[:error] = t("flash.collaborators.wrong_user", uname: params[:member_id])
  126. elsif @platform.add_member(member)
  127. flash[:notice] = t('flash.platform.members.successfully_added', name: member.uname)
  128. else
  129. flash[:error] = t('flash.platform.members.error_in_adding', name: member.uname)
  130. end
  131. redirect_to members_platform_url(@platform)
  132. end
  133. 1 def advisories
  134. authorize @platform
  135. @advisories = @platform.advisories.paginate(page: params[:page])
  136. end
  137. 1 def clear
  138. authorize @platform
  139. @platform.clear
  140. flash[:notice] = t('flash.repository.clear')
  141. redirect_to edit_platform_path(@platform)
  142. end
  143. 1 private
  144. 1 def platform_params
  145. subject_params(Platform)
  146. end
  147. # Private: before_action hook which loads Platform.
  148. 1 def load_platform
  149. authorize @platform = Platform.find_cached(params[:id]), :show? if params[:id]
  150. end
  151. end

app/controllers/platforms/product_build_lists_controller.rb

28.57% lines covered

70 relevant lines. 20 lines covered and 50 lines missed.
    
  1. 1 class Platforms::ProductBuildListsController < Platforms::BaseController
  2. 1 include FileStoreHelper
  3. 1 before_action :authenticate_user!
  4. 1 skip_before_action :authenticate_user!, only: [:index, :show, :log] if APP_CONFIG['anonymous_access']
  5. 1 before_action :redirect_to_full_path_if_short_url, only: [:show, :update]
  6. 1 before_action :load_product, except: :index
  7. 1 before_action :load_product_build_list, except: [:index, :new, :create]
  8. 1 def new
  9. @product_build_list = @product.product_build_lists.new
  10. @product_build_list.params = @product.params
  11. @product_build_list.main_script = @product.main_script
  12. @product_build_list.time_living = @product.time_living
  13. @product_build_list.project_version = @product.project_version
  14. @product_build_list.project = @product.project
  15. unless @product_build_list.project
  16. flash[:error] = t('flash.product_build_list.no_project')
  17. redirect_to edit_platform_product_path(@platform, @product)
  18. end
  19. end
  20. 1 def show
  21. end
  22. 1 def update
  23. @product_build_list.update(not_delete: (params[:product_build_list] || {})[:not_delete])
  24. render :show
  25. end
  26. 1 def cancel
  27. flash[:notice] = if @product_build_list.cancel
  28. t('layout.build_lists.will_be_canceled')
  29. else
  30. t('layout.build_lists.cancel_fail')
  31. end
  32. redirect_back(fallback_location: platform_product_product_build_list_path(
  33. id: @product_build_list.id,
  34. product_id: @product_build_list.product.id,
  35. platform_id: @product_build_list.product.platform_id
  36. )
  37. )
  38. end
  39. 1 def log
  40. worker_log = @product_build_list.abf_worker_log
  41. render json: {
  42. log: (Pygments.highlight(worker_log, lexer: 'sh') rescue worker_log),
  43. building: @product_build_list.build_started?
  44. }
  45. end
  46. 1 def create
  47. pbl = @product.product_build_lists.new product_build_list_params
  48. pbl.project = @product.project
  49. pbl.user = current_user
  50. pbl.base_url = "http://#{request.host_with_port}"
  51. authorize pbl
  52. if pbl.save
  53. flash[:notice] = t('flash.product.build_started')
  54. redirect_to [@platform, @product]
  55. else
  56. flash[:error] = t('flash.product.build_error')
  57. @product_build_list = pbl
  58. render action: :new
  59. end
  60. end
  61. 1 def destroy
  62. if @product_build_list.destroy
  63. flash[:notice] = t('flash.product_build_list.delete')
  64. else
  65. flash[:error] = t('flash.product_build_list.delete_error')
  66. end
  67. redirect_to [@platform, @product]
  68. end
  69. 1 def index
  70. authorize :product_build_list
  71. @product_build_list = ProductBuildList.new(product_build_list_params)
  72. @product_build_list.status = nil if params[:product_build_list].try(:[], :status).blank?
  73. @product_build_lists = @platform.product_build_lists if @platform
  74. @product_build_lists ||= PlatformPolicy::Scope.new(current_user, ProductBuildList.joins(product: :platform)).show
  75. if @product_build_list.product_id.present?
  76. @product_build_lists = @product_build_lists.where(id: @product_build_list.product_id)
  77. else
  78. @product_build_lists = @product_build_lists.
  79. scoped_to_product_name(@product_build_list.product_name).
  80. for_status(@product_build_list.status)
  81. end
  82. @product_build_lists = @product_build_lists.
  83. includes(:project, product: :platform).
  84. recent.paginate(page: current_page)
  85. @build_server_status = AbfWorkerStatusPresenter.new.products_status
  86. end
  87. 1 protected
  88. 1 def product_build_list_params
  89. subject_params(ProductBuildList)
  90. end
  91. 1 def redirect_to_full_path_if_short_url
  92. if params[:platform_id].blank? || params[:product_id].blank?
  93. pbl = ProductBuildList.find params[:id]
  94. product, platform = pbl.product, pbl.product.platform
  95. redirect_to platform_product_product_build_list_path(platform, product, pbl)
  96. end
  97. end
  98. # Private: before_action hook which loads ProductBuildList.
  99. 1 def load_product_build_list
  100. authorize @product_build_list = ProductBuildList.find(params[:id])
  101. end
  102. # Private: before_action hook which loads Product.
  103. 1 def load_product
  104. authorize @product = Product.find(params[:product_id]), :show? if params[:product_id]
  105. end
  106. end

app/controllers/platforms/products_controller.rb

40.0% lines covered

40 relevant lines. 16 lines covered and 24 lines missed.
    
  1. 1 class Platforms::ProductsController < Platforms::BaseController
  2. 1 include GitHelper
  3. 1 before_action :authenticate_user!
  4. 1 skip_before_action :authenticate_user!, only: [:index, :show] if APP_CONFIG['anonymous_access']
  5. 1 before_action :load_product, except: %i(index new create autocomplete_project)
  6. 1 def index
  7. authorize @platform.products.new
  8. @products = @platform.products.paginate(page: params[:page])
  9. end
  10. 1 def new
  11. authorize @product = @platform.products.new
  12. end
  13. 1 def edit
  14. end
  15. 1 def create
  16. authorize @product = @platform.products.build(product_params)
  17. if @product.save
  18. flash[:notice] = t('flash.product.saved')
  19. redirect_to platform_product_path(@platform, @product)
  20. else
  21. flash[:error] = t('flash.product.save_error')
  22. flash[:warning] = @product.errors.map(&:full_message).join('. ')
  23. render action: :new
  24. end
  25. end
  26. 1 def update
  27. if @product.update(product_params)
  28. flash[:notice] = t('flash.product.saved')
  29. redirect_to platform_product_path(@platform, @product)
  30. else
  31. flash[:error] = t('flash.product.save_error')
  32. flash[:warning] = @product.errors.map(&:full_message).join('. ')
  33. render action: "edit"
  34. end
  35. end
  36. 1 def show
  37. @product_build_lists = @product.product_build_lists.default_order.
  38. paginate(page: params[:page])
  39. end
  40. 1 def destroy
  41. @product.destroy
  42. flash[:notice] = t("flash.product.destroyed")
  43. redirect_to platform_products_path(@platform)
  44. end
  45. 1 def autocomplete_project
  46. authorize :project
  47. @items = ProjectPolicy::Scope.new(current_user, Project).membered.
  48. by_owner_and_name(params[:query]).limit(20)
  49. #items.select! {|e| e.repo.branches.count > 0}
  50. end
  51. 1 private
  52. 1 def product_params
  53. subject_params(Product)
  54. end
  55. # Private: before_action hook which loads Product.
  56. 1 def load_product
  57. authorize @product = Product.find(params[:id])
  58. end
  59. end

app/controllers/platforms/repositories_controller.rb

25.93% lines covered

108 relevant lines. 28 lines covered and 80 lines missed.
    
  1. 1 class Platforms::RepositoriesController < Platforms::BaseController
  2. 1 include DatatableHelper
  3. 1 include FileStoreHelper
  4. 1 include RepositoriesHelper
  5. 1 include PaginateHelper
  6. 1 before_action :authenticate_user!
  7. 1 skip_before_action :authenticate_user!, only: [:index, :show, :projects_list] if APP_CONFIG['anonymous_access']
  8. 1 before_action :load_repository, except: [:index, :create, :new]
  9. 1 before_action :set_members, only: [:edit, :update]
  10. 1 before_action -> { @repository = @platform.repositories.find(params[:id]) if params[:id] }
  11. 1 def index
  12. @repositories = @platform.repositories
  13. @repositories = Repository.custom_sort(@repositories).paginate(page: current_page)
  14. end
  15. 1 def show
  16. params[:per_page] = 30
  17. end
  18. 1 def edit
  19. end
  20. 1 def update
  21. authorize @repository
  22. if @repository.update(repository_params)
  23. flash[:notice] = I18n.t("flash.repository.updated")
  24. redirect_to platform_repository_path(@platform, @repository)
  25. else
  26. flash[:error] = I18n.t("flash.repository.update_error")
  27. flash[:warning] = @repository.errors.map(&:full_message).join('. ')
  28. render action: :edit
  29. end
  30. end
  31. 1 def remove_members
  32. User.where(id: params[:members]).find_each do |user|
  33. @repository.remove_member(user)
  34. end
  35. redirect_to edit_platform_repository_path(@platform, @repository)
  36. end
  37. 1 def add_member
  38. if member = User.find_by(id: params[:member_id])
  39. if @repository.add_member(member)
  40. flash[:notice] = t('flash.repository.members.successfully_added', name: member.uname)
  41. else
  42. flash[:error] = t('flash.repository.members.error_in_adding', name: member.uname)
  43. end
  44. end
  45. redirect_to edit_platform_repository_path(@platform, @repository)
  46. end
  47. 1 def new
  48. authorize @repository = @platform.repositories.new
  49. @platform_id = params[:platform_id]
  50. end
  51. 1 def destroy
  52. authorize @repository
  53. @repository.destroy
  54. flash[:notice] = t("flash.repository.destroyed")
  55. redirect_to platform_repositories_path(@repository.platform)
  56. end
  57. 1 def create
  58. authorize @repository = @platform.repositories.build(repository_params)
  59. if @repository.save
  60. flash[:notice] = t('flash.repository.saved')
  61. redirect_to platform_repository_path(@platform, @repository)
  62. else
  63. flash[:error] = t('flash.repository.save_error')
  64. render action: :new
  65. end
  66. end
  67. 1 def add_project
  68. authorize @repository
  69. if projects_list = params.try(:[], :repository).try(:[], :projects_list)
  70. @repository.add_projects projects_list, current_user
  71. redirect_to platform_repository_path(@platform, @repository), notice: t('flash.repository.projects_will_be_added')
  72. return
  73. end
  74. if params[:project_id].present?
  75. @project = Project.find(params[:project_id])
  76. if policy(@project).read?
  77. begin
  78. @repository.projects << @project
  79. flash[:notice] = t('flash.repository.project_added')
  80. rescue ActiveRecord::RecordInvalid
  81. flash[:error] = t('flash.repository.project_not_added')
  82. end
  83. else
  84. flash[:error] = t('flash.repository.no_access_to_read_project')
  85. end
  86. redirect_to platform_repository_path(@platform, @repository)
  87. else
  88. render :projects_list
  89. end
  90. end
  91. 1 def projects_list
  92. render(text: @repository.projects.map(&:name).join("\n")) && return if params[:text] == 'true'
  93. owner_subquery = "
  94. INNER JOIN (
  95. SELECT id, 'User' AS type, uname
  96. FROM users
  97. UNION
  98. SELECT id, 'Group' AS type, uname
  99. FROM groups
  100. ) AS owner
  101. ON projects.owner_id = owner.id AND projects.owner_type = owner.type"
  102. if params[:added] == "true"
  103. @projects = @repository.projects
  104. else
  105. @projects = Project.joins(owner_subquery).addable_to_repository(@repository.id)
  106. @projects = @projects.opened if @repository.platform.main? && !@repository.platform.hidden?
  107. end
  108. # @projects = @projects.paginate(page: page, per_page: per_page)
  109. # @total_projects = @projects.count
  110. @projects = @projects.by_owner(params[:owner_name]).
  111. search_like(params[:project_name]).order("projects.name #{sort_dir}")
  112. @total_items = @projects.count
  113. @projects = @projects.paginate(paginate_params)
  114. respond_to do |format|
  115. format.json {
  116. render partial: (params[:added] == "true") ? 'project' : 'proj_ajax', layout: false
  117. }
  118. end
  119. end
  120. 1 def remove_project
  121. if projects_list = params.try(:[], :repository).try(:[], :projects_list)
  122. @repository.remove_projects projects_list
  123. redirect_to platform_repository_path(@platform, @repository), notice: t('flash.repository.projects_will_be_removed')
  124. end
  125. if params[:project_id].present?
  126. ProjectToRepository.where(project_id: params[:project_id], repository_id: @repository.id).destroy_all
  127. message = t('flash.repository.project_removed')
  128. respond_to do |format|
  129. format.html {redirect_to platform_repository_path(@platform, @repository), notice: message}
  130. format.json {render json: { message: message }}
  131. end
  132. end
  133. end
  134. 1 def regenerate_metadata
  135. authorize @repository
  136. resign_rpms = params[:repository][:resign_rpms] == '1'
  137. if @repository.regenerate(params[:repository].try(:[], :build_for_platform_id), resign_rpms)
  138. flash[:notice] = t('flash.repository.regenerate_in_queue')
  139. else
  140. flash[:error] = t('flash.repository.regenerate_already_in_queue')
  141. end
  142. redirect_to platform_repository_path(@platform, @repository)
  143. end
  144. 1 def sync_lock_file
  145. if params[:remove]
  146. @repository.remove_sync_lock_file
  147. flash[:notice] = t('flash.repository.sync_lock_file_removed')
  148. else
  149. flash[:notice] = t('flash.repository.sync_lock_file_added')
  150. @repository.add_sync_lock_file
  151. end
  152. redirect_to edit_platform_repository_path(@platform, @repository)
  153. end
  154. 1 protected
  155. 1 def repository_params
  156. subject_params(Repository)
  157. end
  158. # Private: before_action hook which loads Repository.
  159. 1 def load_repository
  160. authorize @repository = @platform.repositories.find(params[:id])
  161. end
  162. 1 def set_members
  163. @members = @repository.members.order('name')
  164. end
  165. end

app/controllers/platforms/tokens_controller.rb

34.38% lines covered

32 relevant lines. 11 lines covered and 21 lines missed.
    
  1. 1 class Platforms::TokensController < Platforms::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 before_action :load_token, except: [:index, :create, :new]
  4. 1 def index
  5. authorize @platform, :local_admin_manage?
  6. @tokens = @platform.tokens.includes(:creator, :updater)
  7. .paginate(per_page: 20, page: params[:page])
  8. end
  9. 1 def show
  10. end
  11. 1 def withdraw
  12. if @token.block
  13. @token.updater = current_user
  14. @token.save
  15. flash[:notice] = t('flash.tokens.withdraw_success')
  16. redirect_back(fallback_location: {
  17. id: @token.id,
  18. platform_id: subject_id
  19. })
  20. else
  21. flash[:notice] = t('flash.tokens.withdraw_fail')
  22. redirect_back(fallback_location: {
  23. id: @token.id,
  24. platform_id: subject_id
  25. })
  26. end
  27. end
  28. 1 def new
  29. authorize @token = @platform.tokens.new
  30. end
  31. 1 def create
  32. @token = @platform.tokens.build token_params
  33. @token.creator = current_user
  34. authorize @token
  35. if @token.save
  36. flash[:notice] = t('flash.tokens.saved')
  37. redirect_to platform_tokens_path(@platform)
  38. else
  39. flash[:error] = t('flash.tokens.save_error')
  40. flash[:warning] = @token.errors.map(&:full_message).join('. ') unless @token.errors.empty?
  41. render :new
  42. end
  43. end
  44. 1 protected
  45. 1 def token_params
  46. subject_params(Token)
  47. end
  48. # Private: before_action hook which loads Repository.
  49. 1 def load_token
  50. authorize @token = @platform.tokens.find(params[:id])
  51. end
  52. end

app/controllers/projects/base_controller.rb

76.47% lines covered

17 relevant lines. 13 lines covered and 4 lines missed.
    
  1. 1 class Projects::BaseController < ApplicationController
  2. 1 prepend_before_action :authenticate_user_and_find_project
  3. 1 before_action :init_statistics
  4. 1 protected
  5. 1 def find_collaborators
  6. search = "%#{params[:search_user]}%"
  7. @users = @project.collaborators.where("users.uname ILIKE ?", search)
  8. @users |= @project.owner.members.where("users.uname ILIKE ?", search) if @project.owner.is_a?(Group)
  9. @users = @users.sort_by(&:uname).first(10)
  10. end
  11. 1 def authenticate_user_and_find_project
  12. 3 authenticate_user
  13. 3 return if params[:name_with_owner].blank?
  14. 1 authorize @project = Project.find_by_owner_and_name!(params[:name_with_owner]), :show?
  15. end
  16. 1 def init_statistics
  17. 3 if @project
  18. 1 @opened_issues_count = @project.issues.without_pull_requests.not_closed_or_merged.count
  19. 1 @opened_pull_requests_count = @project.issues.joins(:pull_request).not_closed_or_merged.count
  20. end
  21. end
  22. end

app/controllers/projects/build_lists_controller.rb

29.2% lines covered

137 relevant lines. 40 lines covered and 97 lines missed.
    
  1. 1 class Projects::BuildListsController < Projects::BaseController
  2. 1 include FileStoreHelper
  3. 1 include BuildListsHelper
  4. 1 NESTED_ACTIONS = [:index, :new, :create, :list]
  5. 1 before_action :authenticate_user!
  6. 1 skip_before_action :authenticate_user!, only: [:show, :index, :log] if APP_CONFIG['anonymous_access']
  7. 1 before_action :load_build_list, except: NESTED_ACTIONS
  8. 1 before_action :create_from_build_list, only: :new
  9. 1 def index
  10. authorize :build_list
  11. params[:filter].each{|k,v| params[:filter].delete(k) if v.blank? } if params[:filter]
  12. respond_to do |format|
  13. format.html
  14. format.json do
  15. @filter = BuildList::Filter.new(@project, current_user, params[:filter] || {})
  16. params[:page] = params[:page].to_i == 0 ? nil : params[:page]
  17. params[:per_page] = if BuildList::Filter::PER_PAGE.include? params[:per_page].to_i
  18. params[:per_page].to_i
  19. else
  20. BuildList::Filter::PER_PAGE.first
  21. end
  22. @bls_count = @filter.find.count
  23. @bls = @filter.find.recent.paginate(page: params[:page], per_page: params[:per_page])
  24. @build_lists = BuildList.where(id: @bls.pluck(:id)).recent
  25. .includes(:save_to_platform,
  26. :save_to_repository,
  27. :build_for_platform,
  28. :user,
  29. :source_packages,
  30. project: :project_statistics)
  31. @build_server_status = AbfWorkerStatusPresenter.new.projects_status
  32. end
  33. end
  34. end
  35. 1 def new
  36. 1 authorize @build_list = @project.build_lists.build
  37. 1 if params[:show] == 'inline' && params[:build_list_id].present?
  38. render json: new_build_list_data(@build_list, @project, params), layout: false
  39. else
  40. 1 render :new
  41. end
  42. end
  43. 1 def create
  44. notices, errors = [], []
  45. @repository = Repository.find build_list_params[:save_to_repository_id]
  46. @platform = @repository.platform
  47. build_lists = []
  48. build_for_platforms = Platform.joins(:repositories).where(repositories: { id: build_list_params[:include_repos] }).distinct
  49. Arch.where(id: params[:arches]).each do |arch|
  50. build_for_platforms.find_each do |build_for_platform|
  51. @build_list = @project.build_lists.build(build_list_params)
  52. @build_list.save_to_platform = @platform
  53. @build_list.build_for_platform = build_for_platform
  54. @build_list.arch = arch
  55. @build_list.user = current_user
  56. @build_list.include_repos = @build_list.include_repos.select {|ir| @build_list.build_for_platform.repository_ids.include? ir.to_i}
  57. @build_list.priority = current_user.build_priority # User builds more priority than mass rebuild with zero priority
  58. flash_options = { project_version: @build_list.project_version, arch: arch.name, build_for_platform: build_for_platform.name }
  59. authorize @build_list
  60. if @build_list.save
  61. build_lists << @build_list
  62. notices << t('flash.build_list.saved', flash_options)
  63. else
  64. errors << t('flash.build_list.save_error', flash_options)
  65. end
  66. end
  67. end
  68. errors << t('flash.build_list.no_arch_or_platform_selected') if errors.blank? and notices.blank?
  69. if errors.present?
  70. @build_list ||= BuildList.new
  71. flash[:error] = errors.join('<br>').html_safe
  72. render action: :new
  73. else
  74. BuildList.where(id: build_lists.map(&:id)).update_all(group_id: build_lists[0].id) if build_lists.size > 1
  75. flash[:notice] = notices.join('<br>').html_safe
  76. redirect_to project_build_lists_path(@project)
  77. end
  78. end
  79. 1 def show
  80. @item_groups = @build_list.items.group_by_level
  81. end
  82. 1 def publish
  83. @build_list.update_type = params[:build_list][:update_type] if params[:build_list][:update_type].present?
  84. if params[:attach_advisory].present? and params[:attach_advisory] != 'no' and !@build_list.advisory
  85. unless @build_list.update_type.in? BuildList::RELEASE_UPDATE_TYPES
  86. flash[:notice] = t('layout.build_lists.publish_fail')
  87. redirect_back(fallback_location: build_list_path(@build_list.id))
  88. return
  89. end
  90. if params[:attach_advisory] == 'new'
  91. # create new advisory
  92. unless @build_list.associate_and_create_advisory(advisory_params)
  93. flash[:notice] = t('layout.build_lists.publish_fail')
  94. redirect_back(fallback_location: build_list_path(@build_list.id))
  95. return
  96. end
  97. else
  98. # attach existing advisory
  99. a = Advisory.find_by(advisory_id: params[:attach_advisory])
  100. unless (a && a.attach_build_list(@build_list))
  101. flash[:notice] = t('layout.build_lists.publish_fail')
  102. redirect_back(fallback_location: build_list_path(@build_list.id))
  103. return
  104. end
  105. end
  106. end
  107. @build_list.publisher = current_user
  108. do_and_back(:publish, 'publish_')
  109. end
  110. 1 def dependent_projects
  111. if request.post?
  112. prs = params[:build_list]
  113. if prs.present? && prs[:projects].present? && prs[:arches].present?
  114. project_ids = prs[:projects].select{ |k, v| v == '1' }.keys
  115. arch_ids = prs[:arches]. select{ |k, v| v == '1' }.keys
  116. Resque.enqueue(
  117. BuildLists::DependentPackagesJob,
  118. @build_list.id,
  119. current_user.id,
  120. project_ids,
  121. arch_ids,
  122. {
  123. auto_publish_status: prs[:auto_publish_status],
  124. auto_create_container: prs[:auto_create_container],
  125. include_testing_subrepository: prs[:include_testing_subrepository],
  126. use_cached_chroot: prs[:use_cached_chroot],
  127. use_extra_tests: prs[:use_extra_tests]
  128. }
  129. )
  130. flash[:notice] = t('flash.build_list.dependent_projects_job_added_to_queue')
  131. redirect_to build_list_path(@build_list)
  132. end
  133. end
  134. end
  135. 1 def publish_into_testing
  136. @build_list.publisher = current_user
  137. do_and_back(:publish_into_testing, 'publish_')
  138. end
  139. 1 def rerun_tests
  140. 2 do_and_back(:rerun_tests, 'rerun_tests_')
  141. end
  142. 1 def reject_publish
  143. @build_list.publisher = current_user
  144. do_and_back(:reject_publish, 'reject_publish_')
  145. end
  146. 1 def create_container
  147. do_and_back(:publish_container, 'create_container_')
  148. end
  149. 1 def cancel
  150. do_and_back(:cancel, nil, 'will_be_canceled', 'cancel_fail')
  151. end
  152. 1 def log
  153. render json: {
  154. log: @build_list.log,
  155. building: @build_list.build_started?
  156. }
  157. end
  158. 1 def list
  159. @build_lists = @project.build_lists
  160. @build_lists = @build_lists.where(user_id: current_user) if params[:owner_filter] == 'true'
  161. @build_lists = @build_lists.where(status: [BuildList::BUILD_ERROR, BuildList::FAILED_PUBLISH, BuildList::REJECTED_PUBLISH]) if params[:status_filter] == 'true'
  162. @total_build_lists = @build_lists.count
  163. @build_lists = @build_lists.recent.paginate(page: current_page)
  164. render partial: 'build_lists_ajax', layout: false
  165. end
  166. 1 def update_type
  167. respond_to do |format|
  168. format.html { head :ok }
  169. format.json do
  170. @build_list.update_type = params[:update_type]
  171. if @build_list.save
  172. render json: 'success', status: :ok
  173. else
  174. render json: { message: @build_list.errors.map(&:full_message).join('. ') },
  175. status: :unprocessable_entity
  176. end
  177. end
  178. end
  179. end
  180. 1 protected
  181. 1 def build_list_params
  182. subject_params(BuildList)
  183. end
  184. 1 def advisory_params
  185. permit_params(%i(build_list advisory), *policy(Advisory).permitted_attributes)
  186. end
  187. # Private: before_action hook which loads BuidList.
  188. 1 def load_build_list
  189. 2 authorize @build_list =
  190. 2 if @project
  191. @project.build_lists
  192. else
  193. 2 BuildList
  194. end.find(params[:id])
  195. end
  196. 1 def do_and_back(action, prefix, success = 'success', fail = 'fail')
  197. 2 result = @build_list.send("can_#{action}?") && @build_list.send(action)
  198. 2 message = result ? success : fail
  199. 2 flash[result ? :notice : :error] = t("layout.build_lists.#{prefix}#{message}")
  200. 2 redirect_back(fallback_location: build_list_path(@build_list.id))
  201. end
  202. 1 def create_from_build_list
  203. 1 return if params[:build_list_id].blank?
  204. build_list = @project.build_lists.find(params[:build_list_id])
  205. params[:build_list] = build_list.attributes
  206. params[:arches] = [build_list.arch_id]
  207. [:owner_filter, :status_filter].each { |t| params[t] = 'true' if %w(true undefined).exclude? params[t] }
  208. end
  209. end

app/controllers/projects/collaborators_controller.rb

33.33% lines covered

45 relevant lines. 15 lines covered and 30 lines missed.
    
  1. 1 class Projects::CollaboratorsController < Projects::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 before_action :authorize_collaborators
  4. 1 before_action :find_users
  5. 1 before_action :find_groups
  6. 1 def index
  7. @collaborators = Collaborator.find_by_project(@project)
  8. end
  9. 1 def find
  10. users = User.not_member_of(@project)
  11. groups = Group.not_member_of(@project)
  12. if params[:term].present?
  13. users = users.search_like(params[:term]).first(5)
  14. groups = groups.search_like(params[:term]).first(5)
  15. end
  16. @collaborators = (users | groups).map{|act| Collaborator.new(actor: act, project: @project)}
  17. end
  18. 1 def create
  19. @collaborator = Collaborator.new(collaborator_params)
  20. @collaborator.project = @project
  21. respond_to do |format|
  22. if @collaborator.save
  23. format.json { render partial: 'collaborator', locals: {collaborator: @collaborator, success: true} }
  24. else
  25. format.json { render json: {message:t('flash.collaborators.error_in_adding')}, status: 422 }
  26. end
  27. end
  28. end
  29. 1 def update
  30. cb = Collaborator.find(params[:id])
  31. respond_to do |format|
  32. if cb.update(params[:collaborator])
  33. format.json { render json: {message:t('flash.collaborators.successfully_updated', uname: cb.actor.uname)} }
  34. else
  35. format.json { render json: {message:t('flash.collaborators.error_in_updating')}, status: 422 }
  36. end
  37. end
  38. end
  39. 1 def destroy
  40. cb = Collaborator.find(params[:id])
  41. respond_to do |format|
  42. if cb.present? && cb.destroy
  43. format.json { render json: {message:t('flash.collaborators.successfully_removed', uname: cb.actor.uname)} }
  44. else
  45. format.json {
  46. render json: {message:t('flash.collaborators.error_in_removing', uname: cb.try(:actor).try(:uname))},
  47. status: 422
  48. }
  49. end
  50. end
  51. end
  52. 1 protected
  53. 1 def collaborator_params
  54. subject_params(Collaborator)
  55. end
  56. 1 def find_users
  57. @users = @project.collaborators.order('uname')#User.all
  58. @users = @users.without_ids(@project.owner_id) if @project.owner_type == 'User'
  59. end
  60. 1 def find_groups
  61. @groups = @project.groups.order('uname')#Group.all
  62. @groups = @groups.without_ids(@project.owner_id) if @project.owner_type == 'Group'
  63. end
  64. 1 def authorize_collaborators
  65. authorize @project, :update?
  66. end
  67. end

app/controllers/projects/comments_controller.rb

38.24% lines covered

34 relevant lines. 13 lines covered and 21 lines missed.
    
  1. 1 class Projects::CommentsController < Projects::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 before_action :find_commentable
  4. 1 before_action :find_or_build_comment
  5. 1 include CommentsHelper
  6. 1 def create
  7. respond_to do |format|
  8. if !@comment.set_additional_data params
  9. format.json {
  10. render json: {
  11. message: I18n.t("flash.comment.save_error"),
  12. error: @comment.errors.map(&:full_message)
  13. }
  14. }
  15. elsif @comment.save
  16. format.json {}
  17. else
  18. format.json { render json: { message: I18n.t("flash.comment.save_error") }, status: 422 }
  19. end
  20. end
  21. end
  22. 1 def edit
  23. end
  24. 1 def update
  25. respond_to do |format|
  26. if @comment.update(comment_params)
  27. format.json { render json: {message:t('flash.comment.updated'), body: view_context.markdown(@comment.body)} }
  28. else
  29. format.json { render json: {message:t('flash.comment.error_in_updating')}, status: 422 }
  30. end
  31. end
  32. end
  33. 1 def destroy
  34. respond_to do |format|
  35. if @comment.present? && @comment.destroy
  36. format.json { render json: {message: I18n.t('flash.comment.destroyed')} }
  37. else
  38. format.json {
  39. render json: {message: t('flash.comment.error_in_deleting')}, status: 422 }
  40. end
  41. end
  42. end
  43. 1 protected
  44. 1 def comment_params
  45. subject_params(Comment)
  46. end
  47. 1 def find_commentable
  48. @commentable = params[:issue_id].present? && @project.issues.find_by(serial_id: params[:issue_id]) ||
  49. params[:commit_id].present? && @project.repo.commit(params[:commit_id])
  50. end
  51. 1 def find_or_build_comment
  52. @comment = params[:id].present? && Comment.where(automatic: false).find(params[:id]) ||
  53. current_user.comments.build(comment_params) {|c| c.commentable = @commentable; c.project = @project}
  54. authorize @comment
  55. end
  56. end

app/controllers/projects/commit_subscribes_controller.rb

41.18% lines covered

17 relevant lines. 7 lines covered and 10 lines missed.
    
  1. 1 class Projects::CommitSubscribesController < Projects::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 before_action :find_commit
  4. 1 def create
  5. if Subscribe.subscribe_to_commit(@options)
  6. flash[:notice] = I18n.t("flash.subscribe.commit.saved")
  7. # TODO js
  8. redirect_to commit_path(@project, @commit)
  9. else
  10. flash[:error] = I18n.t("flash.subscribe.saved_error")
  11. redirect_to commit_path(@project, @commit)
  12. end
  13. end
  14. 1 def destroy
  15. Subscribe.unsubscribe_from_commit(@options)
  16. flash[:notice] = t("flash.subscribe.commit.destroyed")
  17. redirect_to commit_path(@project, @commit)
  18. end
  19. 1 protected
  20. 1 def find_commit
  21. @commit = @project.repo.commit(params[:commit_id])
  22. @options = {project_id: @project.id, subscribeable_id: @commit.id.hex, subscribeable_type: @commit.class.name, user_id: current_user.id}
  23. end
  24. end

app/controllers/projects/git/base_controller.rb

76.92% lines covered

13 relevant lines. 10 lines covered and 3 lines missed.
    
  1. 1 class Projects::Git::BaseController < Projects::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 if APP_CONFIG['anonymous_access']
  4. 1 skip_before_action :authenticate_user!, only: %i(show index blame raw archive get_sha1_of_archive diff tags branches)
  5. 1 before_action :authenticate_user, only: %i(show index blame raw archive get_sha1_of_archive diff tags branches)
  6. end
  7. 1 before_action :set_treeish_and_path
  8. 1 before_action :set_branch_and_tree
  9. 1 protected
  10. 1 def set_treeish_and_path
  11. @treeish, @path = params[:treeish].presence || @project.default_head, params[:path]
  12. end
  13. 1 def set_branch_and_tree
  14. @branch = @project.repo.branches.detect{|b| b.name == @treeish}
  15. @tree = @project.repo.tree(@treeish)
  16. # raise Grit::NoSuchPathError if @tree.blobs.blank?
  17. end
  18. end

app/controllers/projects/git/blobs_controller.rb

43.48% lines covered

23 relevant lines. 10 lines covered and 13 lines missed.
    
  1. 1 class Projects::Git::BlobsController < Projects::Git::BaseController
  2. 1 before_action :set_blob
  3. 1 before_action -> {authorize @project, :write? }, only: [:edit, :update]
  4. 1 def show
  5. end
  6. 1 def edit
  7. rugged = @blob.repo.rugged
  8. @lazy = Linguist::LazyBlob.new(rugged, @blob.id, @path, @blob.mode)
  9. end
  10. 1 def update
  11. if @project.update_file(params[:path], params[:content].gsub("\r", ''),
  12. message: params[:message].gsub("\r", ''), actor: current_user, head: @treeish)
  13. flash[:notice] = t("flash.blob.successfully_updated", name: params[:path])
  14. else
  15. flash[:notice] = t("flash.blob.updating_error", name: params[:path])
  16. end
  17. redirect_to action: :show
  18. end
  19. 1 def blame
  20. @blame = Grit::Blob.blame(@project.repo, @commit.id, @path)
  21. end
  22. 1 def raw
  23. repo = Grit::GitRuby::Repository.new(@project.repo.path)
  24. raw = repo.get_raw_object_by_sha1(@blob.id)
  25. send_data raw.content, type: @blob.content_type, disposition: @blob.disposition
  26. end
  27. 1 protected
  28. 1 def set_blob
  29. @blob = @tree / @path or raise Grit::NoSuchPathError
  30. redirect_to tree_path(@project, treeish: @treeish, path: @path) if @blob.is_a? Grit::Tree
  31. @commit = @project.repo.log(@treeish, @path, max_count: 1).first
  32. end
  33. end

app/controllers/projects/git/commits_controller.rb

12.9% lines covered

31 relevant lines. 4 lines covered and 27 lines missed.
    
  1. 1 class Projects::Git::CommitsController < Projects::Git::BaseController
  2. 1 def index
  3. if @path.present?
  4. @commits = @project.repo.log(@treeish, @path)
  5. else
  6. @commits, @page, @last_page = @project.paginate_commits(@treeish, page: params[:page])
  7. end
  8. end
  9. 1 def show
  10. @commit = @commentable = @project.repo.commit(params[:id]) || raise(ActiveRecord::RecordNotFound)
  11. @comments = Comment.for_commit(@commit)
  12. respond_to do |format|
  13. format.html
  14. format.diff { render plain: (@commit.show.map(&:diff).join("\n") rescue ''), content_type: "text/plain" }
  15. format.patch { render plain: (@commit.to_patch rescue ''), content_type: "text/plain" }
  16. end
  17. end
  18. 1 def diff
  19. res = params[:diff].split(/\A(.*)\.\.\.(.*)\z/).select {|e| e.present?}
  20. if res[1].present?
  21. params1 = res[0]
  22. params2 = res[1] == 'HEAD' ? @project.resolve_default_branch : res.last
  23. else # get only one parameter
  24. params1 = @project.resolve_default_branch
  25. params2 = res.first
  26. end
  27. params1.sub! 'HEAD', @project.resolve_default_branch
  28. params2.sub! 'HEAD', @project.resolve_default_branch
  29. ref1 = if @project.repo.branches_and_tags.include? params1
  30. @project.repo.commits(params1).first
  31. else
  32. params1 # possible commit hash
  33. end
  34. @commit1 = @project.repo.commit(ref1) || raise(ActiveRecord::RecordNotFound)
  35. ref = if @project.repo.branches_and_tags.include? params2
  36. @project.repo.commits(params2).first
  37. else
  38. params2 # possible commit hash
  39. end
  40. @commit = @project.repo.commit(ref) || raise(ActiveRecord::RecordNotFound)
  41. @common_ancestor = @project.repo.commit(@project.repo.git.merge_base({}, @commit1, @commit)) || @commit1
  42. @stats = @project.repo.diff_stats @commit1.id, @commit.id
  43. end
  44. end

app/controllers/projects/git/trees_controller.rb

25.37% lines covered

67 relevant lines. 17 lines covered and 50 lines missed.
    
  1. 1 class Projects::Git::TreesController < Projects::Git::BaseController
  2. 1 skip_before_action :set_branch_and_tree, only: [:archive, :get_sha1_of_archive]
  3. 1 skip_before_action :set_treeish_and_path, only: [:archive, :get_sha1_of_archive]
  4. 1 before_action :redirect_to_project, only: :show
  5. 1 before_action :resolve_treeish, only: [:branch, :destroy]
  6. # skip_authorize_resource :project, only: [:destroy, :restore_branch, :create]
  7. 1 before_action -> { authorize(@project, :show?) }, only: [:show, :archive, :tags, :branches, :get_sha1_of_archive]
  8. 1 def show
  9. unless request.xhr?
  10. render('empty') and return if @project.is_empty?
  11. @tree = @tree / @path if @path.present?
  12. @commit = @branch.present? ? @branch.commit() : @project.repo.log(@treeish, @path, max_count: 1).first
  13. raise Grit::NoSuchPathError unless @commit
  14. else
  15. @tree = @tree / @path if @path.present?
  16. end
  17. end
  18. 1 def archive
  19. format, @treeish = params[:format], params[:treeish]
  20. raise Grit::NoSuchPathError unless @treeish =~ /^#{@project.name}-/ &&
  21. @treeish !~ /[\s]+/ &&
  22. format =~ /\A(zip|tar\.gz)\z/
  23. @treeish.gsub!(/^#{@project.name}-/, '')
  24. @commit = @project.repo.commits(@treeish, 1).first
  25. raise Grit::NoSuchPathError unless @commit
  26. tag = @project.repo.tags.find{ |t| t.name == @treeish }
  27. sha1 = @project.get_project_tag_sha1(tag, format) if tag
  28. if sha1.present?
  29. redirect_to "#{APP_CONFIG['file_store_url']}/api/v1/file_stores/#{sha1}"
  30. else
  31. archive = @project.archive_by_treeish_and_format @treeish, format
  32. send_file archive[:path], disposition: 'attachment', type: "application/#{format == 'zip' ? 'zip' : 'x-tar-gz'}", filename: archive[:fullname]
  33. end
  34. end
  35. 1 def get_sha1_of_archive
  36. format, @treeish = params[:format], params[:treeish]
  37. raise Grit::NoSuchPathError unless @treeish =~ /^#{@project.name}-/ &&
  38. @treeish !~ /[\s]+/ &&
  39. format =~ /\A(zip|tar\.gz)\z/
  40. @treeish.gsub!(/^#{@project.name}-/, '')
  41. @commit = @project.repo.commits(@treeish, 1).first
  42. raise Grit::NoSuchPathError unless @commit
  43. tag = @project.repo.tags.find{ |t| t.name == @treeish }
  44. sha1 = @project.get_project_tag_sha1(tag, format) if tag
  45. sha1 ||= ''
  46. render plain: sha1
  47. end
  48. 1 def tags
  49. if request.xhr?
  50. @refs = @project.repo.tags.select{ |t| t.commit }.sort_by(&:name).reverse
  51. render :refs_list
  52. else
  53. respond_to do |format|
  54. format.json { head 422 }
  55. format.html
  56. end
  57. end
  58. end
  59. 1 def restore_branch
  60. authorize @project, :write?
  61. status = @project.create_branch(@treeish, params[:sha], current_user) ? 200 : 422
  62. head status
  63. end
  64. 1 def create
  65. authorize @project, :write?
  66. status = @project.create_branch(params[:new_ref], params[:from_ref], current_user) ? 200 : 422
  67. head status
  68. end
  69. 1 def destroy
  70. authorize @project, :write?
  71. status = @branch && @project.delete_branch(@branch, current_user) ? 200 : 422
  72. head status
  73. end
  74. 1 def branches
  75. if request.xhr?
  76. @refs = @project.repo.branches.sort_by(&:name)
  77. render :refs_list
  78. else
  79. respond_to do |format|
  80. format.json { head 422 }
  81. format.html
  82. end
  83. end
  84. end
  85. 1 protected
  86. 1 def resolve_treeish
  87. raise Grit::NoSuchPathError if params[:treeish] != @branch.try(:name)
  88. end
  89. 1 def redirect_to_project
  90. if params[:treeish] == @project.resolve_default_branch && params[:path].blank? && !request.xhr?
  91. redirect_to @project
  92. end
  93. end
  94. end

app/controllers/projects/hooks_controller.rb

40.63% lines covered

32 relevant lines. 13 lines covered and 19 lines missed.
    
  1. 1 class Projects::HooksController < Projects::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 before_action -> { authorize @project, :update? }
  4. 1 before_action :load_hook, except: %i(index new create)
  5. 1 def index
  6. @name = params[:name]
  7. @hooks = @project.hooks.for_name(@name).order('name asc, created_at desc')
  8. render(:show) if @name.present?
  9. end
  10. 1 def new
  11. @hook = @project.hooks.build
  12. end
  13. 1 def edit
  14. end
  15. 1 def create
  16. authorize @hook = @project.hooks.build(hook_params)
  17. if @hook.save
  18. redirect_to project_hooks_path(@project, name: @hook.name), notice: t('flash.hook.created')
  19. else
  20. flash[:error] = t('flash.hook.save_error')
  21. flash[:warning] = @hook.errors.map(&:full_message).join('. ')
  22. render :new
  23. end
  24. end
  25. 1 def update
  26. if @hook.update(hook_params)
  27. redirect_to project_hooks_path(@project, name: @hook.name), notice: t('flash.hook.updated')
  28. else
  29. flash[:error] = t('flash.hook.save_error')
  30. flash[:warning] = @hook.errors.map(&:full_message).join('. ')
  31. render :edit
  32. end
  33. end
  34. 1 def destroy
  35. @hook.destroy
  36. redirect_to project_hooks_path(@project, name: @hook.name)
  37. end
  38. 1 private
  39. 1 def hook_params
  40. subject_params(Hook)
  41. end
  42. # Private: before_action hook which loads Hook.
  43. 1 def load_hook
  44. authorize @hook = @project.hooks.find(params[:id])
  45. end
  46. end

app/controllers/projects/issues_controller.rb

22.92% lines covered

96 relevant lines. 22 lines covered and 74 lines missed.
    
  1. 1 class Projects::IssuesController < Projects::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 skip_before_action :authenticate_user!, only: [:index, :show, :pull_requests] if APP_CONFIG['anonymous_access']
  4. 1 before_action :load_issue, only: %i(show edit update destroy)
  5. 1 before_action :load_and_authorize_label, only: %i(create_label update_label destroy_label)
  6. 1 before_action :find_collaborators, only: :search_collaborators
  7. 1 layout false, only: [:update, :search_collaborators]
  8. 1 def index
  9. params[:kind] = params[:kind] == 'pull_requests' ? 'pull_requests' : 'issues'
  10. raise Pundit::NotAuthorizedError if !@project.has_issues? && params[:kind] == 'issues'
  11. params[:filter] = params[:filter].in?(['created', 'assigned']) ? params[:filter] : 'all'
  12. params[:sort] = params[:sort] == 'submitted' ? 'submitted' : 'updated'
  13. params[:direction] = params[:direction] == 'asc' ? :asc : :desc
  14. params[:status] = params[:status] == 'closed' ? :closed : :open
  15. if !params[:labels].is_a?(Array) || params[:labels].blank?
  16. params[:labels] = []
  17. end
  18. respond_to do |format|
  19. format.html { render 'index' }
  20. format.json do
  21. all_issues =
  22. if params[:kind] == 'pull_requests'
  23. @project.issues.joins(:pull_request)
  24. else
  25. @project.issues.without_pull_requests
  26. end
  27. @all_issues = all_issues
  28. if current_user
  29. @created_issues = all_issues.where(user_id: current_user)
  30. @assigned_issues = all_issues.where(assignee_id: current_user)
  31. end
  32. case params[:filter]
  33. when 'created'
  34. @issues = @created_issues
  35. when 'assigned'
  36. @issues = @assigned_issues
  37. else
  38. @issues = all_issues
  39. end
  40. if params[:labels].is_a?(Array) && params[:labels].present?
  41. @issues = @issues.joins(:labels).where(labels: {name: params[:labels]})
  42. end
  43. @opened_issues, @closed_issues = @issues.not_closed_or_merged, @issues.closed_or_merged
  44. @issues = @issues.send( params[:status] == :closed ? :closed_or_merged : :not_closed_or_merged )
  45. if params[:sort] == 'submitted'
  46. @issues = @issues.order(created_at: params[:direction])
  47. else
  48. @issues = @issues.order(updated_at: params[:direction])
  49. end
  50. @issues = @issues.includes(:assignee, :user, :pull_request).uniq
  51. .paginate(page: current_page)
  52. render 'index'
  53. end
  54. end
  55. end
  56. 1 def pull_requests
  57. params[:kind] = 'pull_requests'
  58. index
  59. end
  60. 1 def labels
  61. render partial: 'projects/issues/labels.json', locals: {project: @project}, layout: false
  62. end
  63. 1 def new
  64. authorize @issue = @project.issues.build
  65. end
  66. 1 def create
  67. @issue = @project.issues.new
  68. @issue.assign_attributes(issue_params)
  69. @issue.user = current_user
  70. authorize @issue
  71. if @issue.save
  72. @issue.subscribe_creator(current_user.id)
  73. flash[:notice] = I18n.t("flash.issue.saved")
  74. redirect_to project_issues_path(@project)
  75. else
  76. flash[:error] = I18n.t("flash.issue.save_error")
  77. render action: :new
  78. end
  79. end
  80. 1 def show
  81. redirect_to project_pull_request_path(@project, @issue.pull_request) if @issue.pull_request
  82. @commentable = @issue
  83. end
  84. 1 def update
  85. respond_to do |format|
  86. format.html { head :ok }
  87. format.json {
  88. status = 200
  89. if params[:issue] && status = params[:issue][:status]
  90. @issue.set_close(current_user) if status == 'closed'
  91. @issue.set_open if status == 'open'
  92. status = @issue.save ? 200 : 500
  93. else
  94. status = 422 unless @issue.update(issue_params)
  95. end
  96. render status: status
  97. }
  98. end
  99. end
  100. # def destroy
  101. # @issue.destroy
  102. # flash[:notice] = t("flash.issue.destroyed")
  103. # redirect_to root_path
  104. # end
  105. 1 def create_label
  106. @label = @project.labels.new(name: params[:name], color: params[:color])
  107. respond_to do |format|
  108. if @label.save
  109. format.json { render partial: 'labels', locals: {project: @project} }
  110. else
  111. format.json { render plain: @label.errors.map(&:full_message), status: 422 }
  112. end
  113. end
  114. end
  115. 1 def update_label
  116. respond_to do |format|
  117. if @label.update(name: params[:name], color: params[:color])
  118. format.json { render partial: 'labels', locals: {project: @project} }
  119. else
  120. format.json { render plain: @label.errors.map(&:full_message), status: 422 }
  121. end
  122. end
  123. end
  124. 1 def destroy_label
  125. respond_to do |format|
  126. if @label.destroy
  127. format.json { render partial: 'labels', locals: {project: @project} }
  128. else
  129. format.json { render json: @label.errors.map(&:full_message), status: 422 }
  130. end
  131. end
  132. end
  133. 1 def search_collaborators
  134. end
  135. 1 private
  136. 1 def issue_params
  137. subject_params(Issue, @issue)
  138. end
  139. # Private: before_action hook which loads Issue.
  140. 1 def load_issue
  141. authorize @issue = @project.issues.find_by!(serial_id: params[:id])
  142. end
  143. # Private: before_action hook which loads Label.
  144. 1 def load_and_authorize_label
  145. authorize @project, :write?
  146. @label = @project.labels.find(params[:label_id]) if params[:label_id]
  147. end
  148. end

app/controllers/projects/projects_controller.rb

18.57% lines covered

140 relevant lines. 26 lines covered and 114 lines missed.
    
  1. 1 class Projects::ProjectsController < Projects::BaseController
  2. 1 include DatatableHelper
  3. 1 include ProjectsHelper
  4. 1 before_action :authenticate_user!
  5. 1 before_action :who_owns, only: [:new, :create, :mass_import, :run_mass_import]
  6. 1 def index
  7. authorize :project
  8. @projects = ProjectPolicy::Scope.new(current_user, Project).membered.search_like(params[:search])
  9. respond_to do |format|
  10. format.html {
  11. @groups = current_user.groups
  12. @owners = User.where(id: @projects.where(owner_type: 'User').uniq.pluck(:owner_id))
  13. }
  14. format.json {
  15. groups = params[:groups] || []
  16. owners = params[:users] || []
  17. @projects = @projects.by_owners(groups, owners) if groups.present? || owners.present?
  18. @projects_count = @projects.count
  19. @projects = @projects.recent.paginate(page: current_page, per_page: Project.per_page)
  20. }
  21. end
  22. end
  23. 1 def new
  24. authorize :project
  25. @project = Project.new
  26. end
  27. 1 def mass_import
  28. authorize :project
  29. @project = Project.new(mass_import: true)
  30. end
  31. 1 def run_mass_import
  32. @project = Project.new project_params
  33. @project.owner = choose_owner
  34. authorize @project
  35. @project.valid?
  36. @project.errors.messages.slice! :url
  37. if @project.errors.messages.blank? # We need only url validation
  38. @project.init_mass_import
  39. flash[:notice] = t('flash.project.mass_import_added_to_queue')
  40. redirect_to projects_path
  41. else
  42. render :mass_import
  43. end
  44. end
  45. 1 def edit
  46. authorize @project
  47. @project_aliases = Project.project_aliases(@project).paginate(page: current_page)
  48. end
  49. 1 def create
  50. @project = Project.new project_params
  51. @project.owner = choose_owner
  52. authorize @project
  53. if @project.save
  54. flash[:notice] = t('flash.project.saved')
  55. redirect_to @project
  56. else
  57. flash[:error] = t('flash.project.save_error')
  58. flash[:warning] = @project.errors.map(&:full_message).join('. ')
  59. render action: :new
  60. end
  61. end
  62. 1 def update
  63. authorize @project
  64. params[:project].delete(:maintainer_id) if params[:project][:maintainer_id].blank?
  65. respond_to do |format|
  66. format.html do
  67. if @project.update(project_params)
  68. flash[:notice] = t('flash.project.saved')
  69. redirect_to @project
  70. else
  71. flash[:error] = t('flash.project.save_error')
  72. flash[:warning] = @project.errors.map(&:full_message).join('. ')
  73. render action: :edit
  74. end
  75. end
  76. format.json do
  77. if @project.update(project_params)
  78. render json: { notice: I18n.t('flash.project.saved') }
  79. else
  80. render json: { error: I18n.t('flash.project.save_error') }, status: 422
  81. end
  82. end
  83. end
  84. end
  85. 1 def schedule
  86. authorize @project
  87. p_to_r = @project.project_to_repositories.find_by(repository_id: params[:repository_id])
  88. unless p_to_r.repository.publish_without_qa
  89. authorize p_to_r.repository.platform, :local_admin_manage?
  90. end
  91. p_to_r.user_id = current_user.id
  92. p_to_r.enabled = params[:enabled].present?
  93. p_to_r.auto_publish = params[:auto_publish].present?
  94. p_to_r.save
  95. if p_to_r.save
  96. render json: { notice: I18n.t('flash.project.saved') }.to_json
  97. else
  98. render json: { error: I18n.t('flash.project.save_error') }.to_json, status: 422
  99. end
  100. end
  101. 1 def destroy
  102. authorize @project
  103. @project.destroy
  104. flash[:notice] = t("flash.project.destroyed")
  105. redirect_to @project.owner
  106. end
  107. 1 def fork(is_alias = false)
  108. owner = (Group.find params[:group] if params[:group].present?) || current_user
  109. authorize owner, :write?
  110. if forked = @project.fork(owner, new_name: params[:fork_name], is_alias: is_alias) and forked.valid?
  111. redirect_to forked, notice: t("flash.project.forked")
  112. else
  113. flash[:warning] = t("flash.project.fork_error")
  114. flash[:error] = forked.errors.map(&:full_message).join("\n")
  115. redirect_to @project
  116. end
  117. end
  118. 1 def alias
  119. authorize @project
  120. fork(true)
  121. end
  122. 1 def possible_forks
  123. authorize @project
  124. render partial: 'projects/git/base/forks', layout: false,
  125. locals: { owner: current_user, name: (params[:name].presence || @project.name) }
  126. end
  127. 1 def sections
  128. authorize @project, :update?
  129. if request.patch?
  130. if @project.update(project_params)
  131. flash[:notice] = t('flash.project.saved')
  132. redirect_to sections_project_path(@project)
  133. else
  134. @project.save
  135. flash[:error] = t('flash.project.save_error')
  136. end
  137. end
  138. end
  139. 1 def remove_user
  140. authorize @project
  141. @project.relations.by_actor(current_user).destroy_all
  142. respond_to do |format|
  143. format.html do
  144. flash[:notice] = t("flash.project.user_removed")
  145. redirect_to projects_path
  146. end
  147. format.json { head :ok }
  148. end
  149. end
  150. 1 def autocomplete_maintainers
  151. authorize @project
  152. term, limit = params[:query], params[:limit] || 10
  153. items = User.member_of_project(@project)
  154. .where("users.name ILIKE ? OR users.uname ILIKE ?", "%#{term}%", "%#{term}%")
  155. .limit(limit).map { |u| {name: u.fullname, id: u.id} }
  156. render json: items
  157. end
  158. 1 def preview
  159. authorize @project
  160. respond_to do |format|
  161. format.json {}
  162. format.html {render inline: view_context.markdown(params[:text]), layout: false}
  163. end
  164. end
  165. 1 def refs_list
  166. authorize @project
  167. refs = @project.repo.branches_and_tags.map(&:name)
  168. @selected = params[:selected] if refs.include?(params[:selected])
  169. @selected ||= @project.resolve_default_branch
  170. render layout: false
  171. end
  172. 1 protected
  173. 1 def project_params
  174. subject_params(Project)
  175. end
  176. 1 def who_owns
  177. t = @project.try(:owner_type)
  178. @who_owns = if t.nil?
  179. :me
  180. else
  181. t == 'User' ? :me : :group
  182. end
  183. end
  184. 1 def choose_owner
  185. if params[:who_owns] == 'group'
  186. Group.find(params[:owner_id])
  187. else
  188. current_user
  189. end
  190. end
  191. end

app/controllers/projects/pull_requests_controller.rb

17.27% lines covered

110 relevant lines. 19 lines covered and 91 lines missed.
    
  1. 1 class Projects::PullRequestsController < Projects::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 skip_before_action :authenticate_user!, only: [:index, :show] if APP_CONFIG['anonymous_access']
  4. 1 before_action :load_issue, except: %i(index autocomplete_to_project new create)
  5. 1 before_action :load_pull, except: %i(index autocomplete_to_project new create)
  6. 1 def new
  7. to_project = find_destination_project(false)
  8. authorize to_project, :show?
  9. @pull = to_project.pull_requests.new
  10. @issue = @pull.issue = to_project.issues.new
  11. set_attrs
  12. authorize @pull
  13. if PullRequest.check_ref(@pull, 'to', @pull.to_ref) && PullRequest.check_ref(@pull, 'from', @pull.from_ref) || @pull.uniq_merge
  14. flash.now[:warning] = @pull.errors.map(&:full_message).join('. ')
  15. else
  16. @pull.check(false) # don't make event transaction
  17. if @pull.already?
  18. @pull.destroy
  19. flash.now[:warning] = I18n.t('projects.pull_requests.up_to_date', to_ref: @pull.to_ref, from_ref: @pull.from_ref)
  20. else
  21. load_diff_commits_data
  22. end
  23. end
  24. end
  25. 1 def create
  26. unless pull_params
  27. redirect :back
  28. end
  29. to_project = find_destination_project
  30. authorize to_project, :show?
  31. @pull = to_project.pull_requests.build pull_params
  32. @issue = @pull.issue
  33. @pull.issue.assignee_id = (params[:issue] || {})[:assignee_id] if policy(to_project).write?
  34. @pull.issue.user, @pull.issue.project, @pull.from_project = current_user, to_project, @project
  35. @pull.from_project_owner_uname = @pull.from_project.owner.uname
  36. @pull.from_project_name = @pull.from_project.name
  37. @pull.issue.new_pull_request = true
  38. authorize @pull
  39. if @pull.valid? # FIXME more clean/clever logics
  40. @pull.save # set pull id
  41. @pull.reload
  42. @pull.check(false) # don't make event transaction
  43. if @pull.already?
  44. @pull.destroy
  45. flash.now[:error] = I18n.t('projects.pull_requests.up_to_date', to_ref: @pull.to_ref, from_ref: @pull.from_ref)
  46. render :new
  47. else
  48. @pull.send(@pull.status == 'blocked' ? 'block' : @pull.status)
  49. redirect_to project_pull_request_path(@pull.to_project, @pull)
  50. end
  51. else
  52. flash.now[:error] = t('flash.pull_request.save_error')
  53. flash.now[:warning] = @pull.errors.map(&:full_message).join('. ')
  54. if @pull.errors.try(:messages) && @pull.errors.messages[:to_ref].nil? && @pull.errors.messages[:from_ref].nil?
  55. @pull.check(false) # don't make event transaction
  56. load_diff_commits_data
  57. end
  58. render :new
  59. end
  60. end
  61. 1 def merge
  62. authorize @pull
  63. status = @pull.merge!(current_user) ? 200 : 422
  64. head status
  65. end
  66. 1 def update
  67. authorize @pull
  68. status = 422
  69. if (action = params[:pull_request_action]) && %w(close reopen).include?(params[:pull_request_action])
  70. if @pull.send("can_#{action}?")
  71. @pull.set_user_and_time current_user
  72. @pull.send(action)
  73. @pull.check if @pull.open?
  74. status = 200
  75. end
  76. end
  77. head status
  78. end
  79. 1 def show
  80. if @pull.nil?
  81. redirect_to project_issue_path(@project, @issue)
  82. return
  83. end
  84. load_diff_commits_data
  85. if params[:get_activity] == 'true'
  86. render partial: 'activity', layout: false
  87. elsif params[:get_diff] == 'true'
  88. render partial: 'diff_tab', layout: false
  89. elsif params[:get_commits] == 'true'
  90. render partial: 'commits_tab', layout: false
  91. end
  92. end
  93. 1 def autocomplete_to_project
  94. items = []
  95. term = params[:query].to_s.strip.downcase
  96. [ Project.where(id: @project.pull_requests.last.try(:to_project_id)),
  97. @project.ancestors,
  98. ProjectPolicy::Scope.new(current_user, Project).membered
  99. ].each do |p|
  100. items.concat p.by_owner_and_name(term)
  101. end
  102. items = items.uniq{|i| i.id}.select{|e| e.repo.branches.count > 0}
  103. render json: json_for_autocomplete_base(items)
  104. end
  105. 1 protected
  106. # Private: before_action hook which loads Issue.
  107. 1 def load_issue
  108. @issue = @project.issues.find_by!(serial_id: params[:id])
  109. end
  110. # Private: before_action hook which loads PullRequest.
  111. 1 def load_pull
  112. @pull = @issue.pull_request
  113. authorize @pull, :show? if @pull
  114. end
  115. 1 def pull_params
  116. @pull_params ||= subject_params(PullRequest).presence
  117. end
  118. 1 def json_for_autocomplete_base items
  119. items.collect do |project|
  120. {id: project.id.to_s, name: project.name_with_owner}
  121. end
  122. end
  123. 1 def load_diff_commits_data
  124. @commits = @pull.repo.commits_between(@pull.to_commit, @pull.from_commit)
  125. @total_commits = @commits.count
  126. @commits = @commits.last(100)
  127. @stats = @pull.diff_stats
  128. @comments, @commentable = @issue.comments, @issue
  129. end
  130. 1 def find_destination_project bang=true
  131. project = Project.find_by_owner_and_name params[:to_project]
  132. raise ActiveRecord::RecordNotFound if bang && !project
  133. project || @project.pull_requests.last.try(:to_project) || @project.root
  134. end
  135. 1 def set_attrs
  136. if pull_params && pull_params[:issue_attributes]
  137. @pull.issue.title = pull_params[:issue_attributes][:title].presence
  138. @pull.issue.body = pull_params[:issue_attributes][:body].presence
  139. end
  140. @pull.from_project = @project
  141. @pull.to_ref = (pull_params[:to_ref].presence if pull_params) || @pull.to_project.default_head
  142. @pull.from_ref = params[:treeish].presence || (pull_params[:from_ref].presence if pull_params) || @pull.from_project.default_head(params[:treeish])
  143. @pull.from_project_owner_uname = @pull.from_project.owner.uname
  144. @pull.from_project_name = @pull.from_project.name
  145. end
  146. end

app/controllers/projects/subscribes_controller.rb

38.89% lines covered

18 relevant lines. 7 lines covered and 11 lines missed.
    
  1. 1 class Projects::SubscribesController < Projects::BaseController
  2. 1 before_action :authenticate_user!
  3. 1 before_action :load_issue
  4. 1 def create
  5. authorize @subscribe = @issue.subscribes.build(user_id: current_user.id)
  6. if @subscribe.save
  7. flash[:notice] = I18n.t("flash.subscribe.saved")
  8. redirect_back(fallback_location: '/')
  9. else
  10. flash[:error] = I18n.t("flash.subscribe.saved_error")
  11. redirect_back(fallback_location: '/')
  12. end
  13. end
  14. 1 def destroy
  15. authorize @subscribe = @issue.subscribes.find_by(user_id: current_user.id)
  16. @subscribe.destroy
  17. flash[:notice] = t("flash.subscribe.destroyed")
  18. redirect_back(fallback_location: '/')
  19. end
  20. 1 private
  21. # Private: before_action hook which loads Issue.
  22. 1 def load_issue
  23. authorize @issue = @project.issues.find_by!(serial_id: params[:issue_id]), :show?
  24. end
  25. end

app/controllers/projects/wiki_controller.rb

18.58% lines covered

183 relevant lines. 34 lines covered and 149 lines missed.
    
  1. #require 'lib/gollum'
  2. 1 require 'cgi'
  3. 1 class Projects::WikiController < Projects::BaseController
  4. 1 WIKI_OPTIONS = {}
  5. 1 before_action :authenticate_user!
  6. 1 skip_before_action :authenticate_user!, only: [:show, :index, :git, :compare, :compare_wiki, :history, :wiki_history, :search, :pages] if APP_CONFIG['anonymous_access']
  7. 1 before_action :authorize_read_actions, only: [:index, :show, :git, :compare, :compare_wiki, :history, :wiki_history, :search, :pages]
  8. 1 before_action :authorize_write_actions, only: [:edit, :update, :new, :create, :destroy, :revert, :revert_wiki, :preview]
  9. 1 before_action :get_wiki
  10. 1 def index
  11. @name = 'Home'
  12. @page = @wiki.page(@name)
  13. show_or_create_page
  14. end
  15. 1 def show
  16. @name = CGI.unescape(params[:id])
  17. redirect_to project_wiki_index_path(@project) and return if @name == 'Home'
  18. ref = params[:ref].presence || @wiki.ref
  19. @page = @wiki.page(@name, ref)
  20. if !@page && @wiki.page(@name)
  21. flash[:error] = t('flash.wiki.ref_not_exist')
  22. redirect_to project_wiki_path(@project, CGI.escape(@name)) and return
  23. end
  24. show_or_create_page
  25. end
  26. 1 def edit
  27. @name = CGI.unescape(params[:id])
  28. if page = @wiki.page(@name)
  29. @page = page
  30. @content = page.text_data
  31. render :edit
  32. else
  33. render :new
  34. end
  35. end
  36. 1 def update
  37. @name = CGI.unescape(params[:id])
  38. @page = @wiki.page(@name)
  39. name = wiki_page_params[:rename] || @name
  40. update_wiki_page(@wiki, @page, wiki_page_params[:content], {committer: committer}, name, wiki_page_params[:format])
  41. update_wiki_page(@wiki, @page.footer, wiki_page_params[:footer], {committer: committer}) if wiki_page_params[:footer]
  42. update_wiki_page(@wiki, @page.sidebar, wiki_page_params[:sidebar], {committer: committer}) if wiki_page_params[:sidebar]
  43. committer.commit
  44. flash[:notice] = t('flash.wiki.successfully_updated', name: @name)
  45. redirect_to project_wiki_path(@project, CGI.escape(@name))
  46. end
  47. 1 def new
  48. @name = ''
  49. @new = true
  50. end
  51. 1 def create
  52. @name = CGI.unescape(wiki_page_params[:page])
  53. format = wiki_page_params[:format].intern
  54. begin
  55. @wiki.write_page(@name, format, wiki_page_params[:content] || '', {committer: committer}).commit
  56. redirect_to project_wiki_path(@project, CGI.escape(@name))
  57. rescue Gollum::DuplicatePageError => e
  58. flash[:error] = t("flash.wiki.duplicate_page", name: @name)
  59. render :new
  60. end
  61. end
  62. 1 def destroy
  63. @name = CGI.unescape(params[:id])
  64. page = @wiki.page(@name)
  65. if page
  66. @wiki.delete_page(page, {committer: committer}).commit
  67. flash[:notice] = t("flash.wiki.page_successfully_removed")
  68. else
  69. flash[:notice] = t("flash.wiki.page_not_found", name: params[:id])
  70. end
  71. redirect_to project_wiki_index_path(@project)
  72. end
  73. 1 def git
  74. end
  75. 1 def compare
  76. @name = CGI.unescape(params[:id])
  77. if request.post?
  78. @versions = params[:versions] || []
  79. if @versions.size < 2
  80. redirect_to history_project_wiki_path(@project, CGI.escape(@name))
  81. else
  82. redirect_to compare_versions_project_wiki_path(@project, CGI.escape(@name),
  83. sprintf('%s...%s', @versions.last, @versions.first))
  84. end
  85. elsif request.get?
  86. @versions = params[:versions].split(/\.{2,3}/)
  87. if @versions.size < 2
  88. redirect_to history_project_wiki_path(@project, CGI.escape(@name))
  89. return
  90. end
  91. @page = @wiki.page(@name)
  92. @diffs = [@wiki.repo.diff(@versions.first, @versions.last, @page.path).first]
  93. render :compare
  94. else
  95. redirect_to project_wiki_path(@project, CGI.escape(@name))
  96. end
  97. end
  98. 1 def compare_wiki
  99. if request.post?
  100. @versions = params[:versions] || []
  101. versions_string = case @versions.size
  102. when 1 then @versions.first
  103. when 2 then sprintf('%s...%s', @versions.last, @versions.first)
  104. else begin
  105. redirect_to history_project_wiki_index_path(@project)
  106. return
  107. end
  108. end
  109. redirect_to compare_versions_project_wiki_index_path(@project, versions_string)
  110. elsif request.get?
  111. @versions = params[:versions].split(/\.{2,3}/) || []
  112. @diffs = case @versions.size
  113. when 1 then @wiki.repo.commit_diff(@versions.first)
  114. when 2 then @wiki.repo.diff(@versions.first, @versions.last)
  115. else begin
  116. redirect_to history_project_wiki_index_path(@project)
  117. return
  118. end
  119. end
  120. render :compare
  121. else
  122. redirect_to project_wiki_path(@project, CGI.escape(@name))
  123. end
  124. end
  125. 1 def revert
  126. @name = CGI.unescape(params[:id])
  127. @page = @wiki.page(@name)
  128. sha1 = params[:sha1]
  129. sha2 = params[:sha2]
  130. sha2 = nil if params[:sha2] == 'prev'
  131. if c = @wiki.revert_page(@page, sha1, sha2, {committer: committer}) and c.commit
  132. flash[:notice] = t("flash.wiki.revert_success")
  133. redirect_to project_wiki_path(@project, CGI.escape(@name))
  134. else
  135. # if revert wasn't successful then redirect back to comparsion.
  136. # if second commit version is missed, then second version is
  137. # params[:sha1] and first version is parent of params[:sha1]
  138. # (see Gollum::Wiki#revert_page)
  139. sha2, sha1 = sha1, "#{sha1}^" if !sha2
  140. @versions = [sha1, sha2]
  141. diffs = @wiki.repo.diff(@versions.first, @versions.last, @page.path)
  142. @diffs = [diffs.first]
  143. flash[:error] = t("flash.wiki.patch_does_not_apply")
  144. render :compare
  145. end
  146. end
  147. 1 def revert_wiki
  148. sha1 = params[:sha1]
  149. sha2 = params[:sha2]
  150. sha2 = nil if sha2 == 'prev'
  151. if c = @wiki.revert_commit(sha1, sha2, {committer: committer}) and c.commit
  152. flash[:notice] = t("flash.wiki.revert_success")
  153. redirect_to project_wiki_index_path(@project)
  154. else
  155. sha2, sha1 = sha1, "#{sha1}^" if !sha2
  156. @versions = [sha1, sha2]
  157. @diffs = @wiki.repo.diff(@versions.first, @versions.last)
  158. flash[:error] = t("flash.wiki.patch_does_not_apply")
  159. render :compare
  160. end
  161. end
  162. 1 def preview
  163. @name = wiki_page_params[:page]
  164. @page = @wiki.preview_page(@name, wiki_page_params[:content], wiki_page_params[:format])
  165. @content = @page.formatted_data
  166. @editable = false
  167. render :show
  168. end
  169. 1 def history
  170. @name = CGI.unescape(params[:id])
  171. if @page = @wiki.page(@name)
  172. @versions = @page.versions
  173. else
  174. redirect_back(fallback_location: '/')
  175. end
  176. end
  177. 1 def wiki_history
  178. @versions = @wiki.log
  179. render :history
  180. end
  181. 1 def search
  182. @query = params[:q]
  183. @results = @wiki.search @query
  184. end
  185. 1 def pages
  186. @results = @wiki.pages
  187. @ref = @wiki.ref
  188. end
  189. 1 protected
  190. 1 def get_wiki
  191. @wiki = Gollum::Wiki.new(@project.wiki_path,
  192. WIKI_OPTIONS.merge(base_path: project_wiki_index_path(@project)))
  193. end
  194. # This method was grabbed from sinatra application, shipped with Gollum gem.
  195. # See Gollum gem and Gollum License if you have any questions about license notes.
  196. # https://github.com/github/gollum https://github.com/github/gollum/blob/master/LICENSE
  197. 1 def update_wiki_page(wiki, page, content, commit_msg, name = nil, format = nil)
  198. return if !page ||
  199. ((!content || page.raw_data == content) && page.format == format)
  200. name ||= page.name
  201. format = (format || page.format).to_sym
  202. content ||= page.raw_data
  203. wiki.update_page(page, name, format, content.to_s, commit_msg)
  204. end
  205. 1 def commit_message
  206. msg = wiki_page_params[:message].presence
  207. unless msg
  208. msg = case action_name.to_s
  209. when 'create' then "Created page #{@name.to_s}"
  210. when 'update' then "Updated page #{@name.to_s}"
  211. when 'destroy' then "Removed page #{@name.to_s}"
  212. when 'revert' then "Reverted page #{@name.to_s}"
  213. when 'revert_wiki' then "Reverted wiki"
  214. end
  215. msg << " (#{wiki_page_params[:format]})" if wiki_page_params[:format]
  216. end
  217. msg = 'Unhandled action' if !msg || msg.empty?
  218. { message: msg }
  219. end
  220. 1 def committer
  221. unless @committer
  222. p = commit_message.merge({name: current_user.uname, email: current_user.email})
  223. @committer = Gollum::Committer.new(@wiki, p)
  224. GitHook.perform_later!(:notification, :process, {project_id: @project.id, actor_name: @committer.actor.name, commit_sha: @committer.commit})
  225. end
  226. @committer
  227. end
  228. 1 def show_or_create_page
  229. if @page
  230. @content = @page.formatted_data
  231. @editable = policy(@project).write?
  232. render :show
  233. elsif file = @wiki.file(@name)
  234. render plain: file.raw_data, content_type: file.mime_type
  235. elsif policy(@project).write?
  236. @new = true
  237. render :new
  238. else
  239. redirect_to action: :index #forbidden_path
  240. end
  241. end
  242. 1 def wiki_page_params
  243. @wiki_page_params ||= params[:wiki_page] || {}
  244. end
  245. 1 def authorize_read_actions
  246. authorize @project, :show?
  247. end
  248. 1 def authorize_write_actions
  249. authorize @project, :write?
  250. end
  251. end

app/controllers/robots_controller.rb

75.0% lines covered

4 relevant lines. 3 lines covered and 1 lines missed.
    
  1. 1 class RobotsController < ApplicationController
  2. 1 skip_after_action :verify_authorized
  3. 1 def index
  4. render file: 'sitemap/robots', layout: false, content_type: Mime::TEXT
  5. end
  6. end

app/controllers/search_controller.rb

55.56% lines covered

9 relevant lines. 5 lines covered and 4 lines missed.
    
  1. 1 class SearchController < ApplicationController
  2. 1 include PaginateHelper
  3. 1 before_action :authenticate_user! unless APP_CONFIG['anonymous_access']
  4. 1 skip_after_action :verify_authorized
  5. 1 def index
  6. @type = Search::TYPES.find{ |t| t == params[:type] } || Search::TYPES.first
  7. @query = params[:query]
  8. @search = Search.new(@query, current_user, paginate_params)
  9. @collection = @search.send(@type)
  10. end
  11. end

app/controllers/statistics_controller.rb

11.63% lines covered

43 relevant lines. 5 lines covered and 38 lines missed.
    
  1. 1 class StatisticsController < ApplicationController
  2. RANGES = [
  3. 1 RANGE_TWENTY_FOUR_HOURS = 'twenty_four_hours',
  4. RANGE_LAST_7_DAYS = 'last_7_days',
  5. RANGE_LAST_30_DAYS = 'last_30_days',
  6. RANGE_LAST_60_DAYS = 'last_60_days',
  7. RANGE_LAST_90_DAYS = 'last_90_days',
  8. RANGE_LAST_180_DAYS = 'last_180_days',
  9. RANGE_LAST_YEAR = 'last_year',
  10. RANGE_CUSTOM = 'custom',
  11. ]
  12. 1 def index
  13. authorize :statistic
  14. respond_to do |format|
  15. format.html
  16. format.json do
  17. init_variables
  18. render json: StatisticPresenter.new(
  19. range_start: @range_start,
  20. range_end: @range_end,
  21. unit: @unit,
  22. users_or_groups: params[:users_or_groups]
  23. )
  24. end
  25. end
  26. end
  27. 1 private
  28. 1 def init_variables
  29. case params[:range]
  30. when RANGE_TWENTY_FOUR_HOURS
  31. @range_end = Time.now.utc
  32. @range_start = @range_end - 1.day
  33. @unit = :hour
  34. when RANGE_LAST_7_DAYS
  35. @range_end = Date.today
  36. @range_start = @range_end - 7.days
  37. @unit = :day
  38. when RANGE_LAST_30_DAYS
  39. @range_end = Date.today
  40. @range_start = @range_end - 30.days
  41. @unit = :day
  42. when RANGE_LAST_60_DAYS
  43. @range_end = Date.today
  44. @range_start = @range_end - 30.days
  45. @unit = :day
  46. when RANGE_LAST_90_DAYS
  47. @range_end = Date.today
  48. @range_start = @range_end - 90.days
  49. @unit = :day
  50. when RANGE_LAST_180_DAYS
  51. @range_end = Date.today
  52. @range_start = @range_end - 180.days
  53. @unit = :month
  54. when RANGE_LAST_YEAR
  55. @range_end = Date.today
  56. @range_start = @range_end - 1.year
  57. @unit = :month
  58. when RANGE_CUSTOM
  59. @range_start = Time.zone.parse(params[:range_start]).utc
  60. @range_end = Time.zone.parse(params[:range_end]).utc
  61. diff = @range_end - @range_start
  62. @unit =
  63. if diff <= 24.hours
  64. :hour
  65. elsif diff <= 90.days
  66. :day
  67. else
  68. :month
  69. end
  70. else
  71. raise ActiveRecord::RecordNotFound
  72. end
  73. rescue ArgumentError
  74. raise ActiveRecord::RecordNotFound
  75. end
  76. end

app/controllers/users/base_controller.rb

66.67% lines covered

9 relevant lines. 6 lines covered and 3 lines missed.
    
  1. 1 class Users::BaseController < ApplicationController
  2. 1 before_action :authenticate_user!
  3. 1 before_action :find_user
  4. 1 protected
  5. 1 def find_user
  6. if user_id = params[:uname] || params[:user_id] || params[:id]
  7. @user = User.opened.find_by_insensitive_uname! user_id
  8. end
  9. end
  10. 1 def set_current_user
  11. @user = current_user
  12. end
  13. end

app/controllers/users/profile_controller.rb

25.0% lines covered

16 relevant lines. 4 lines covered and 12 lines missed.
    
  1. 1 class Users::ProfileController < Users::BaseController
  2. 1 include PaginateHelper
  3. 1 skip_before_action :authenticate_user!, only: :show if APP_CONFIG['anonymous_access']
  4. 1 def show
  5. authorize @user
  6. respond_to do |format|
  7. format.html do
  8. @groups = @user.groups.order(:uname)
  9. end
  10. format.json do
  11. @projects = @user.own_projects.search_like(params[:term]).recent
  12. case params[:visibility]
  13. when 'open'
  14. @projects = @projects.opened
  15. when 'hidden'
  16. @projects = ProjectPolicy::Scope.new(current_user, @projects.by_visibilities('hidden')).read
  17. else
  18. @projects = ProjectPolicy::Scope.new(current_user, @projects).read
  19. end
  20. @total_items = @projects.count
  21. @projects = @projects.paginate(paginate_params)
  22. end
  23. end
  24. end
  25. end

app/controllers/users/registrations_controller.rb

25.0% lines covered

36 relevant lines. 9 lines covered and 27 lines missed.
    
  1. 1 class Users::RegistrationsController < Devise::RegistrationsController
  2. 1 before_action :update_sanitized_params, if: :devise_controller?
  3. 1 before_action :check_captcha, only: [:create]
  4. 1 def new
  5. super do |resource|
  6. if params[:invite_key].to_s.strip.empty?
  7. resource.invite_key = ''
  8. else
  9. invite = Invite.find_by_invite_key(params[:invite_key])
  10. if !invite || invite.used?
  11. flash[:error] = I18n.t('errors.messages.bad_invite_key')
  12. resource.invite_key = ''
  13. else
  14. resource.invite_key = params[:invite_key]
  15. end
  16. end
  17. end
  18. end
  19. 1 def create
  20. invite_key = params[:user][:invite_key]
  21. invite = Invite.find_by_invite_key(invite_key)
  22. if !invite || invite.used?
  23. flash[:error] = I18n.t('errors.messages.bad_invite_key')
  24. self.resource = resource_class.new sign_up_params
  25. resource.validate
  26. set_minimum_password_length
  27. render :new
  28. else
  29. super do |r|
  30. if r.persisted?
  31. invite.invited_user = r
  32. invite.save
  33. end
  34. end
  35. end
  36. end
  37. 1 protected
  38. 1 def update_sanitized_params
  39. devise_parameter_sanitizer.for(:sign_up) do |u|
  40. u.permit(:invite_key, :uname, :name, :email, :password, :password_confirmation)
  41. end
  42. end
  43. 1 private
  44. 1 def check_captcha
  45. unless verify_recaptcha
  46. self.resource = resource_class.new sign_up_params
  47. resource.validate
  48. set_minimum_password_length
  49. render :new
  50. end
  51. end
  52. end

app/controllers/users/settings_controller.rb

27.12% lines covered

59 relevant lines. 16 lines covered and 43 lines missed.
    
  1. 1 class Users::SettingsController < Users::BaseController
  2. 1 include AvatarHelper
  3. 1 skip_before_action :find_user
  4. 1 before_action :set_current_user
  5. 1 before_action -> { authorize @user, :update? }
  6. 1 def profile
  7. if request.patch?
  8. send_confirmation = params[:user][:email] != @user.email
  9. if @user.update_without_password(user_params)
  10. update_avatar(@user, params)
  11. if send_confirmation
  12. @user.confirmed_at = @user.confirmation_sent_at = nil
  13. @user.send_confirmation_instructions
  14. end
  15. flash[:notice] = t('flash.user.saved')
  16. redirect_to profile_settings_path and return
  17. end
  18. flash[:error] = t('flash.user.save_error')
  19. flash[:warning] = @user.errors.map(&:full_message).join('. ')
  20. end
  21. end
  22. 1 def reset_auth_token
  23. @user.reset_authentication_token!
  24. flash[:notice] = t("flash.user.reset_auth_token")
  25. redirect_to profile_settings_path
  26. end
  27. 1 def private
  28. if request.patch?
  29. if @user.update_with_password(user_params)
  30. flash[:notice] = t('flash.user.saved')
  31. redirect_to private_settings_path and return
  32. end
  33. flash[:error] = t('flash.user.save_error')
  34. flash[:warning] = @user.errors.map(&:full_message).join('. ')
  35. end
  36. end
  37. 1 def invites
  38. authorize :invite
  39. @invites = Invite.owned(@user).order('id desc')
  40. end
  41. 1 def create_invite
  42. authorize :invite
  43. invite = Invite.create(
  44. user_id: @user.id
  45. )
  46. if invite.valid?
  47. flash[:success] = I18n.t("flash.invite.created")
  48. redirect_to invites_settings_path
  49. else
  50. flash[:error] = invite.errors.map(&:full_message).join('. ')
  51. redirect_to invites_settings_path
  52. end
  53. end
  54. 1 def notifiers
  55. if request.patch?
  56. if @user.notifier.update(settings_notifier_params)
  57. flash[:notice] = I18n.t("flash.settings.saved")
  58. redirect_to notifiers_settings_path and return
  59. end
  60. flash[:error] = I18n.t("flash.settings.save_error")
  61. end
  62. end
  63. 1 def builds_settings
  64. @user.builds_setting ||= @user.build_builds_setting
  65. if request.patch?
  66. if @user.builds_setting.update(user_builds_setting_params)
  67. flash[:notice] = I18n.t("flash.settings.saved")
  68. redirect_to builds_settings_settings_path and return
  69. end
  70. flash[:error] = I18n.t("flash.settings.save_error")
  71. end
  72. end
  73. 1 private
  74. 1 def settings_notifier_params
  75. subject_params(SettingsNotifier)
  76. end
  77. 1 def user_params
  78. subject_params(User)
  79. end
  80. 1 def user_builds_setting_params
  81. subject_params(UserBuildsSetting)
  82. end
  83. end

app/controllers/users/ssh_keys_controller.rb

40.91% lines covered

22 relevant lines. 9 lines covered and 13 lines missed.
    
  1. 1 class Users::SshKeysController < Users::BaseController
  2. 1 before_action :set_current_user
  3. 1 before_action -> { authorize current_user, :update? }
  4. 1 skip_before_action :find_user
  5. 1 def index
  6. @ssh_key = SshKey.new
  7. end
  8. 1 def create
  9. @ssh_key = current_user.ssh_keys.new ssh_key_params
  10. if @ssh_key.save
  11. flash[:notice] = t 'flash.ssh_keys.saved'
  12. else
  13. flash[:error] = t 'flash.ssh_keys.save_error'
  14. flash[:warning] = @ssh_key.errors.map(&:full_message).join('. ') unless @ssh_key.errors.empty?
  15. end
  16. redirect_to ssh_keys_path
  17. end
  18. 1 def destroy
  19. @ssh_key = current_user.ssh_keys.find params[:id]
  20. if @ssh_key.destroy
  21. flash[:notice] = t 'flash.ssh_keys.destroyed'
  22. else
  23. flash[:error] = t 'flash.ssh_keys.destroy_error'
  24. end
  25. redirect_to ssh_keys_path
  26. end
  27. 1 private
  28. 1 def ssh_key_params
  29. subject_params(SshKey)
  30. end
  31. end

app/controllers/users/users_controller.rb

47.37% lines covered

19 relevant lines. 9 lines covered and 10 lines missed.
    
  1. 1 class Users::UsersController < Users::BaseController
  2. 1 skip_before_action :authenticate_user!, only: [:allowed, :check, :discover]
  3. 1 skip_after_action :verify_authorized
  4. 1 before_action :find_user_by_key, only: [:allowed, :discover]
  5. 1 def allowed
  6. project = Project.find_by_owner_and_name! params[:project]
  7. pp = ProjectPolicy.new(@user, project)
  8. can = case params[:action_type]
  9. when 'git-upload-pack'
  10. pp.read?
  11. when 'git-receive-pack'
  12. pp.write?
  13. end
  14. render inline: (!@user.access_locked? && can).to_s
  15. end
  16. 1 def check
  17. head :ok
  18. end
  19. 1 def discover
  20. render json: {name: @user.name}.to_json
  21. end
  22. 1 protected
  23. 1 def find_user_by_key
  24. key = SshKey.find(params[:key_id])
  25. @user = key.user
  26. end
  27. end

app/helpers/active_admin/admin_helper.rb

75.0% lines covered

4 relevant lines. 3 lines covered and 1 lines missed.
    
  1. 1 module ActiveAdmin::AdminHelper
  2. 1 include ActiveAdmin::Views
  3. 1 def admin_polymorphic_path(resource)
  4. self.send("admin_#{resource.class.to_s.underscore}_path", resource)
  5. end
  6. end

app/helpers/activity_feeds_helper.rb

33.33% lines covered

18 relevant lines. 6 lines covered and 12 lines missed.
    
  1. 1 module ActivityFeedsHelper
  2. 1 def render_activity_feed(activity_feed)
  3. render activity_feed.partial, activity_feed.data.merge(activity_feed: activity_feed)
  4. end
  5. 1 def get_feed_title_from_content(content)
  6. # removes html tags and haml generator indentation whitespaces and new line chars:
  7. feed_title = strip_tags(content).gsub(/(^\s+|\n| )/, ' ')
  8. # removes multiple whitespaces in a row and strip it:
  9. feed_title = feed_title.gsub(/\s{2,}/, ' ').strip
  10. end
  11. 1 def get_user_from_activity_item(item)
  12. email = item.data[:creator_email]
  13. User.where(email: email).first || User.new(email: email) if email.present?
  14. end
  15. 1 def user_link(user, user_name, full_url = false)
  16. user.persisted? ? link_to(user_name, full_url ? user_url(user) : user_path(user)) : user_name
  17. end
  18. 1 def get_feed_build_list_status_message(status)
  19. message, error = case status
  20. when BuildList::BUILD_PENDING
  21. ['pending', nil]
  22. when BuildList::BUILD_PUBLISHED
  23. ['published', nil]
  24. when BuildList::SUCCESS
  25. ['success', nil]
  26. else ['failed', t("layout.build_lists.statuses.#{BuildList::HUMAN_STATUSES[status]}")]
  27. end
  28. " #{t("notifications.bodies.build_status.#{message}", error: error)}"
  29. end
  30. end

app/helpers/advisories_helper.rb

33.33% lines covered

12 relevant lines. 4 lines covered and 8 lines missed.
    
  1. 1 module AdvisoriesHelper
  2. 1 def advisories_select_options(advisories, opts = {class: 'popoverable'})
  3. def_values = [[t("layout.advisories.no_"), 'no'], [t("layout.advisories.new"), 'new'], [t("layout.advisories.existing"), 'existing', {class: 'advisory_id'}]]
  4. options_for_select(def_values, def_values.first)
  5. end
  6. 1 def advisory_id_for_hint
  7. sprintf(Advisory::ID_STRING_TEMPLATE, type: "{#{Advisory::TYPES.values.join(',')}}",
  8. year: 'YYYY', id: 'XXXX')
  9. end
  10. 1 def construct_ref_link(ref)
  11. ref = sanitize(ref)
  12. url = if ref =~ %r[^http(s?)://*]
  13. ref
  14. else
  15. 'http://' << ref
  16. end
  17. link_to url, url
  18. end
  19. end

app/helpers/application_helper.rb

18.03% lines covered

61 relevant lines. 11 lines covered and 50 lines missed.
    
  1. 1 module ApplicationHelper
  2. 1 def submit_button_tag(icon_class: 'fa-check', text: nil)
  3. text ||= I18n.t('layout.save')
  4. button_tag type: :submit,
  5. data: {'disable-with' => I18n.t('layout.processing')},
  6. class: 'btn btn-primary' do
  7. content_tag(:i, nil, class: ['fa', icon_class]) << ' '<< text
  8. end
  9. end
  10. 1 def layout_class
  11. case
  12. when controller_name == 'issues' && action_name == 'new'
  13. 'right nopadding'
  14. when controller_name == 'build_lists' && ['new', 'create'].include?(action_name)
  15. nil
  16. when controller_name == 'platforms' && ['build_all', 'mass_builds'].include?(action_name)
  17. 'right slim'
  18. when controller_name == 'platforms' && action_name == 'show'
  19. 'right bigpadding'
  20. when controller_name == 'platforms' && action_name == 'clone'
  21. 'right middlepadding'
  22. when controller_name == 'contacts' && action_name == 'sended'
  23. 'all feedback_sended'
  24. else
  25. content_for?(:sidebar) ? 'right' : 'all'
  26. end
  27. end
  28. 1 def top_menu_class(base)
  29. (controller_name.include?('build_lists') ? controller_name : params[:controller]).include?(base.to_s) ? 'active' : nil
  30. end
  31. # Public: Get icon css class.
  32. #
  33. # base - the tab (Symbol).
  34. #
  35. # Returns String css class.
  36. 1 def top_menu_icon(base)
  37. case base
  38. when :platforms
  39. 'fa-linux'
  40. when :projects
  41. 'fa-cube'
  42. when :build_lists
  43. 'fa-cogs'
  44. when :groups
  45. 'fa-users'
  46. when :advisories
  47. 'fa-newspaper-o'
  48. when :statistics
  49. 'fa-area-chart'
  50. end
  51. end
  52. 1 def title_object(object)
  53. return object.advisory_id if object.class == Advisory
  54. name = object.class == Group ? object.uname : object.name
  55. object_name = t "activerecord.models.#{object.class.name.downcase}"
  56. case object.class.name
  57. when 'Project'
  58. "#{object_name} #{object.owner.uname}/#{object.name}"
  59. when 'Platform'
  60. if object.main?
  61. "#{object_name} #{object.name}"
  62. else
  63. "#{object_name} #{object.owner.uname}/#{object.name}"
  64. end
  65. when 'Repository', 'Product'
  66. "#{object_name} #{object.name} - #{title_object object.platform}"
  67. when 'Group'
  68. "#{object_name} #{object.uname}"
  69. else object.class.name
  70. end
  71. end
  72. 1 def local_alert(text, type = 'error')
  73. html = "<div class='flash'><div class='alert #{type}'> #{text}"
  74. html << link_to('×', '#', class: 'close close-alert', 'data-dismiss' => 'alert')
  75. html << '</div></div>'
  76. end
  77. # Why 42? Because it is the Answer!
  78. 1 def short_message(message, length = 42)
  79. truncate(message, length: length, omission: '…')
  80. end
  81. 1 def datetime_moment(date, options = {})
  82. tag = options[:tag] || :div
  83. klass = "datetime_moment #{options[:class]}"
  84. content_tag(tag, nil, class: klass, origin_datetime: date)
  85. end
  86. 1 def alert_class(type)
  87. case type
  88. when 'error', 'alert'
  89. 'alert-danger'
  90. when 'notice'
  91. 'alert-success'
  92. else
  93. "alert-#{type}"
  94. end
  95. end
  96. 1 def bytes_to_size(bytes)
  97. sizes = [0, 1024, 1024*1024, 1024*1024*1024]
  98. names = ['B', 'KiB', 'MiB', 'GiB']
  99. sizes.each_with_index do |l, i|
  100. low, high = sizes[i], sizes[i+1]
  101. if bytes >= low && (!high || bytes < high)
  102. if low == 0
  103. sz = bytes
  104. else
  105. sz = (bytes.to_f / low).round(2)
  106. end
  107. return "#{sz}#{names[i]}"
  108. end
  109. end
  110. end
  111. end

app/helpers/avatar_helper.rb

40.0% lines covered

5 relevant lines. 2 lines covered and 3 lines missed.
    
  1. 1 module AvatarHelper
  2. 1 def update_avatar(subject, params)
  3. if subject.avatar && params[:delete_avatar] == '1'
  4. subject.avatar = nil
  5. subject.save
  6. end
  7. end
  8. end

app/helpers/build_lists_helper.rb

26.06% lines covered

142 relevant lines. 37 lines covered and 105 lines missed.
    
  1. 1 module BuildListsHelper
  2. # See: app/assets/javascripts/angularjs/models/build_list.js.erb
  3. 1 def build_list_status_color(status)
  4. case status
  5. when BuildList::BUILD_PUBLISHED, BuildList::SUCCESS, BuildList::BUILD_PUBLISHED_INTO_TESTING
  6. 'success'
  7. when BuildList::BUILD_ERROR, BuildList::FAILED_PUBLISH, BuildList::REJECTED_PUBLISH, BuildList::FAILED_PUBLISH_INTO_TESTING, BuildList::PACKAGES_FAIL, BuildList::UNPERMITTED_ARCH
  8. 'error'
  9. when BuildList::TESTS_FAILED
  10. 'warning'
  11. else
  12. 'nocolor'
  13. end
  14. end
  15. 1 def can_run_dependent_build_lists?(build_list)
  16. build_list.save_to_platform.main? &&
  17. build_list.save_to_platform.distrib_type == 'mdv'
  18. end
  19. 1 def availables_main_platforms
  20. Platform.availables_main_platforms current_user
  21. end
  22. 1 def dependent_projects(package)
  23. return [] if package.dependent_packages.blank?
  24. packages = BuildList::Package.
  25. select('build_list_packages.project_id, build_list_packages.name').
  26. joins(:build_list).
  27. where(
  28. platform_id: package.platform,
  29. name: package.dependent_packages,
  30. package_type: package.package_type,
  31. build_lists: { status: BuildList::BUILD_PUBLISHED }
  32. ).
  33. group('build_list_packages.project_id, build_list_packages.name').
  34. reorder(:project_id).group_by(&:project_id)
  35. Project.where(id: packages.keys).recent.map do |project|
  36. [
  37. project,
  38. packages[project.id].map(&:name).sort
  39. ]
  40. end
  41. end
  42. 1 def external_nodes
  43. BuildList::EXTERNAL_NODES.map do |type|
  44. [I18n.t("layout.build_lists.external_nodes.#{type}"), type]
  45. end
  46. end
  47. 1 def auto_publish_statuses
  48. BuildList::AUTO_PUBLISH_STATUSES.map do |status|
  49. [I18n.t("layout.build_lists.auto_publish_status.#{status}"), status]
  50. end
  51. end
  52. 1 def mass_build_options
  53. options_for_select(
  54. MassBuild.recent.limit(15).pluck(:name, :id).unshift([t(:none), -1])
  55. )
  56. end
  57. 1 def build_list_options_for_new_core
  58. [
  59. [I18n.t("layout.true_"), 1],
  60. [I18n.t("layout.false_"), 0]
  61. ]
  62. end
  63. 1 def build_list_item_status_color(status)
  64. case status
  65. when BuildList::SUCCESS
  66. 'success'
  67. when BuildList::BUILD_ERROR, BuildList::Item::GIT_ERROR #, BuildList::DEPENDENCIES_ERROR
  68. 'error'
  69. else
  70. ''
  71. end
  72. end
  73. 1 def build_list_classified_update_types
  74. advisoriable = BuildList::RELEASE_UPDATE_TYPES.map do |el|
  75. [el, {class: 'advisoriable'}]
  76. end
  77. nonadvisoriable = (BuildList::UPDATE_TYPES - BuildList::RELEASE_UPDATE_TYPES).map do |el|
  78. [el, {class: 'nonadvisoriable'}]
  79. end
  80. return advisoriable + nonadvisoriable
  81. end
  82. 1 def build_list_item_version_link(item, str_version = false)
  83. hash_size=5
  84. if item.version =~ /^[\da-z]+$/ && item.name == item.build_list.project.name
  85. bl = item.build_list
  86. {
  87. text: str_version ? "#{shortest_hash_id item.version, hash_size}" : shortest_hash_id(item.version, hash_size),
  88. href: commit_path(bl.project, item.version)
  89. }
  90. else
  91. {}
  92. end
  93. end
  94. 1 def build_list_version_name(bl)
  95. hash_size=5
  96. if bl.commit_hash.present?
  97. if bl.last_published_commit_hash.present? && bl.last_published_commit_hash != bl.commit_hash
  98. "#{shortest_hash_id bl.last_published_commit_hash, hash_size}...#{shortest_hash_id bl.commit_hash, hash_size}"
  99. else
  100. shortest_hash_id(bl.commit_hash, hash_size)
  101. end
  102. else
  103. bl.project_version
  104. end
  105. end
  106. 1 def get_build_list_version_path(bl)
  107. if bl.commit_hash.present?
  108. if bl.last_published_commit_hash.present? && bl.last_published_commit_hash != bl.commit_hash
  109. diff_path(bl.project, bl.last_published_commit_hash) + "...#{bl.commit_hash}"
  110. else
  111. commit_path(bl.project, bl.commit_hash)
  112. end
  113. else
  114. nil
  115. end
  116. end
  117. 1 def build_list_version_link(bl)
  118. hash_size=5
  119. if bl.commit_hash.present?
  120. if bl.last_published_commit_hash.present? && bl.last_published_commit_hash != bl.commit_hash
  121. link_to "#{shortest_hash_id bl.last_published_commit_hash, hash_size}...#{shortest_hash_id bl.commit_hash, hash_size}",
  122. diff_path(bl.project, bl.last_published_commit_hash) + "...#{bl.commit_hash}"
  123. else
  124. link_to shortest_hash_id(bl.commit_hash, hash_size), commit_path(bl.project, bl.commit_hash)
  125. end
  126. else
  127. bl.project_version
  128. end
  129. end
  130. 1 def product_build_list_version_link(bl, str_version = false)
  131. if bl.commit_hash.present?
  132. link_to str_version ? "#{shortest_hash_id bl.commit_hash} ( #{bl.project_version} )" : shortest_hash_id(bl.commit_hash),
  133. commit_path(bl.project, bl.commit_hash)
  134. else
  135. bl.project_version
  136. end
  137. end
  138. 1 def container_url(build_list = @build_list)
  139. url = "#{APP_CONFIG['downloads_url']}/#{build_list.save_to_platform.name}/container/#{build_list.id}/"
  140. if ['dnf', 'mdv'].include?(build_list.build_for_platform.try(:distrib_type))
  141. url << "#{build_list.arch.name}/#{build_list.save_to_repository.name}/release/"
  142. end
  143. url.html_safe
  144. end
  145. 1 def can_publish_in_future?(bl)
  146. [
  147. BuildList::SUCCESS,
  148. BuildList::FAILED_PUBLISH,
  149. BuildList::BUILD_PUBLISHED,
  150. BuildList::TESTS_FAILED,
  151. BuildList::BUILD_PUBLISHED_INTO_TESTING
  152. ].include?(bl.status)
  153. end
  154. 1 def log_reload_time_options
  155. t = I18n.t("layout.build_lists.log.reload_times").map { |i| i.reverse }
  156. options_for_select(t, t.first).html_safe
  157. end
  158. 1 def log_reload_lines_options
  159. options_for_select([100, 200, 500, 1000, 1500, 2000], 1000).html_safe
  160. end
  161. 1 def get_version_release build_list
  162. pkg = build_list.source_packages.first
  163. "#{pkg.version}-#{pkg.release}" if pkg.present?
  164. end
  165. 1 def new_build_list_data(build_list, project, params)
  166. res = {
  167. build_list_id: params[:build_list_id],
  168. name_with_owner: project.name_with_owner,
  169. build_for_platform_id: params[:build_list].try(:[], :build_for_platform_id),
  170. save_to_repository_id: save_to_repository_id(params),
  171. project_version: project_version(project, params),
  172. platforms: new_build_list_platforms(params),
  173. save_to_repositories: save_to_repositories(project, params),
  174. project_versions: build_list_project_versions(project),
  175. arches: arches(params),
  176. default_extra_repos: default_extra_repos(project),
  177. extra_repos: extra_repos(params),
  178. extra_build_lists: extra_build_lists(params),
  179. auto_create_container: default_auto_create_container(params, build_list),
  180. auto_publish_status: params[:build_list].try(:[], :auto_publish_status)
  181. }
  182. res.to_json
  183. end
  184. 1 def is_repository_checked(repo, params)
  185. include_repos(params).include? repo.id.to_s
  186. end
  187. 1 def filter_by_save_to_platform
  188. pls = availables_main_platforms
  189. pls = pls.select{ |p| current_user_platforms.include?(p.id) } if current_user_platforms.present?
  190. pls.map{ |pl| [pl.name, pl.id] }
  191. end
  192. 1 private
  193. 1 def save_to_repositories(project, params)
  194. project.repositories.map do |r|
  195. # Show only main platforms which user used as default.
  196. next if r.platform.main? && current_user_platforms.present? && current_user_platforms.exclude?(r.platform.id)
  197. {
  198. id: r.id,
  199. name: "#{r.platform.name}/#{r.name}",
  200. publish_without_qa: r.publish_without_qa?,
  201. repo_name: r.name,
  202. platform_id: r.platform.id,
  203. default_branch: r.platform.default_branch,
  204. default_arches: ( r.platform.platform_arch_settings.by_default.pluck(:arch_id).presence ||
  205. Arch.where(name: Arch::DEFAULT).pluck(:id) )
  206. }
  207. end.compact.sort_by { |e| e[:name] }
  208. end
  209. 1 def new_build_list_platforms(params)
  210. availables_main_platforms.map do |pl|
  211. # Show only main platforms which user used as default.
  212. next if current_user_platforms.present? && current_user_platforms.exclude?(pl.id)
  213. platform = { id: pl.id, name: pl.name, repositories: [] }
  214. Repository.custom_sort(pl.repositories).each do |repo|
  215. platform[:repositories] << { id: repo.id,
  216. name: repo.name,
  217. disabled: false,
  218. checked: is_repository_checked(repo, params) }
  219. end
  220. platform
  221. end.compact
  222. end
  223. 1 def current_user_platforms
  224. @current_user_platforms ||= (current_user.try(:builds_setting).try(:platforms) || []).select(&:present?).map(&:to_i)
  225. end
  226. 1 def include_repos(params)
  227. @include_repos ||= (params.try(:[], :build_list).try(:[], :include_repos) || []).map {|e| e.to_s}
  228. end
  229. 1 def save_to_repository_id(params)
  230. @save_to_repository_id ||= params[:build_list].try(:[], :save_to_repository_id).to_i
  231. end
  232. 1 def project_version(project, params)
  233. @project_version ||= params[:build_list].try(:[], :project_version) || project.resolve_default_branch
  234. end
  235. 1 def build_list_project_versions(project)
  236. return [] unless project
  237. branches_kind = I18n.t('layout.git.repositories.branches')
  238. tags_kind = I18n.t('layout.git.repositories.tags')
  239. res = []
  240. project.repo.branches.each do |br|
  241. res << { name: br.name, kind: branches_kind }
  242. end
  243. project.repo.tags.each do |t|
  244. res << { name: t.name, kind: tags_kind }
  245. end
  246. res.sort_by { |e| e[:name] }
  247. end
  248. 1 def arches(params)
  249. Arch.recent.map do |arch|
  250. {
  251. id: arch.id,
  252. name: arch.name,
  253. checked: (params[:arches]||[]).include?(arch.id) ||
  254. (params[:arches].blank? &&
  255. controller.action_name == 'new' &&
  256. Arch::DEFAULT.include?(arch.name))
  257. }
  258. end
  259. end
  260. 1 def default_extra_repos(project)
  261. scope = project.repositories.joins(:platform).where(platforms: { platform_type: 'personal' })
  262. scope = PlatformPolicy::Scope.new(current_user, scope).show
  263. scope.map do |extra|
  264. {
  265. id: extra.id,
  266. platform_id: extra.platform.id,
  267. label: "#{extra.platform.name}/#{extra.name}",
  268. path: url_for([extra.platform, extra])
  269. }
  270. end
  271. end
  272. 1 def extra_repos(params)
  273. Repository.where(id: params[:build_list].try(:[], :extra_repositories) ).map do |extra|
  274. {
  275. id: extra.id,
  276. label: "#{extra.platform.name}/#{extra.name}",
  277. path: url_for([extra.platform, extra])
  278. }
  279. end
  280. end
  281. 1 def extra_build_lists(params)
  282. BuildList.where(id: params[:build_list].try(:[], :extra_build_lists) ).map do |extra|
  283. {
  284. id: extra.id,
  285. label: "#{extra.id} (#{extra.project.name} - #{extra.arch.name})",
  286. path: url_for(extra)
  287. }
  288. end
  289. end
  290. 1 def default_auto_create_container(params, build_list)
  291. checked = params[:build_list].try(:[], :auto_create_container)
  292. checked = build_list.auto_create_container if checked.nil?
  293. checked
  294. end
  295. end

app/helpers/comments_helper.rb

27.78% lines covered

18 relevant lines. 5 lines covered and 13 lines missed.
    
  1. 1 module CommentsHelper
  2. 1 def project_commentable_comment_path(project, commentable, comment)
  3. if Comment.issue_comment?(commentable.class)
  4. project_issue_comment_path(project, commentable, comment)
  5. elsif Comment.commit_comment?(commentable.class)
  6. project_commit_comment_path(project, commentable, comment)
  7. end
  8. end
  9. 1 def project_commentable_path(project, commentable)
  10. if Comment.issue_comment?(commentable.class)
  11. polymorphic_path [project, commentable.pull_request ? commentable.pull_request : commentable]
  12. elsif Comment.commit_comment?(commentable.class)
  13. commit_path project, commentable.id
  14. end
  15. end
  16. 1 def project_commentable_comments_path(project, commentable)
  17. if commentable.is_a? Issue
  18. project_issue_comments_path(@project, @commentable)
  19. elsif commentable.is_a? Grit::Commit
  20. project_commit_comments_path(@project, @commentable)
  21. end
  22. end
  23. 1 def comment_anchor c
  24. "#{(c.data.present? && c.actual_inline_comment?) ? 'diff-' : ''}comment#{c.id}"
  25. end
  26. end

app/helpers/commit_helper.rb

15.15% lines covered

132 relevant lines. 20 lines covered and 112 lines missed.
    
  1. 1 module CommitHelper
  2. 1 MAX_FILES_WITHOUT_COLLAPSE = 25
  3. 1 def render_commit_stats(options = {})
  4. stats = options[:stats]
  5. diff = options[:diff]
  6. repo = options[:repo]
  7. commit = options[:commit]
  8. parent_commit = commit.parents.try(:first)
  9. res = ["<ul class='list-group boffset0'>"]
  10. ind=0
  11. stats.files.each do |filename, adds, deletes, total|
  12. file_name = get_filename_in_diff(diff[ind], filename)
  13. file_status = t "layout.projects.diff.#{get_file_status_in_diff(diff[ind])}"
  14. res << "<li class='list-group-item'>"
  15. res << "<div class='row'>"
  16. res << "<div class='col-sm-8'>"
  17. res << "<a href='#diff-#{ind}' data-toggle='tooltip' data-placement='top' title='#{file_status}'>"
  18. res << "#{diff_file_icon(diff[ind])} #{h(file_name)}"
  19. res << "</a></div>"
  20. res << render_file_changes(diff: diff[ind], adds: adds, deletes: deletes, total: total,
  21. repo: repo, commit: commit, parent_commit: parent_commit, file_status: file_status)
  22. res << "</div"
  23. res << "</li>"
  24. ind +=1
  25. end
  26. res << "</ul>"
  27. wrap_commit_header_list(stats, res)
  28. end
  29. 1 def wrap_commit_header_list(stats, list)
  30. is_stats_open = stats.files.count <= MAX_FILES_WITHOUT_COLLAPSE ? 'in' : ''
  31. res = ["<div class='panel-group' id='diff_header' role='tablist' aria-multiselectable='false'>"]
  32. res << "<div class='panel panel-default'>"
  33. res << "<div class='panel-heading' role='tab' id='heading'>"
  34. res << "<h4 class='panel-title'>"
  35. res << "<a data-toggle='collapse' data-parent='#diff_header' href='#collapseList' aria-expanded='true' aria-controls='collapseList'>"
  36. res << "<span class='fa fa-chevron-#{is_stats_open ? 'down' : 'up'}'></span>"
  37. res << " #{diff_commit_header_message(stats)}</a>"
  38. res << "</h4>"
  39. res << "</div>"
  40. res << "<div id='collapseList' class='panel-collapse collapse #{is_stats_open}' role='tabpanel' aria-labelledby='collapseList'>"
  41. res << "<div class='panel-body'>"
  42. res += list
  43. res << "</div>"
  44. res << "</div>"
  45. res << "</div>"
  46. res << "</div>"
  47. res.join("\n").html_safe
  48. end
  49. 1 def diff_commit_header_message(stats)
  50. t("layout.projects.diff_show_header",
  51. files: t("layout.projects.commit_files_count", count: stats.files.size),
  52. additions: t("layout.projects.commit_additions_count", count: stats.additions),
  53. deletions: t("layout.projects.commit_deletions_count", count: stats.deletions))
  54. end
  55. 1 def commit_date(date)
  56. I18n.localize(date, { format: "%d %B %Y" })
  57. end
  58. 1 def short_hash_id(id)
  59. id[0..19]
  60. end
  61. 1 def shortest_hash_id(id, size=10)
  62. id[0..size-1]
  63. end
  64. 1 def commit_author_link(author)
  65. name = author.name
  66. email = author.email
  67. u = User.where(email: email).first
  68. u.present? ? link_to(name, user_path(u)) : mail_to(email, name)
  69. end
  70. 1 def commits_pluralize(commits_count)
  71. Russian.p(commits_count, *commits_pluralization_arr)
  72. end
  73. 1 def is_file_open_in_diff(blob, diff)
  74. return true if blob.binary? && blob.render_as == :image
  75. return true if diff.diff.blank? && diff.a_mode != diff.b_mode
  76. diff.diff.present? && diff.diff.split("\n").count <= DiffHelper::MAX_LINES_WITHOUT_COLLAPSE
  77. end
  78. 1 def file_blob_in_diff(repo, commit_id, diff)
  79. return if repo.nil? || commit_id.nil? || diff.nil?
  80. tree = repo.tree(commit_id)
  81. blob = diff.renamed_file ? (tree / diff.b_path) : (tree / (diff.a_path || diff.b_path))
  82. blob || diff.a_blob || diff.b_blob
  83. end
  84. 1 def get_commit_id_for_file(diff, commit, parent_commit)
  85. diff.deleted_file ? parent_commit.id : commit.id
  86. end
  87. 1 def get_file_status_in_diff(diff)
  88. if diff.renamed_file
  89. :renamed_file
  90. elsif diff.new_file
  91. :new_file
  92. elsif diff.deleted_file
  93. :deleted_file
  94. else
  95. :changed_file
  96. end
  97. end
  98. 1 def get_filename_in_diff(diff, filename)
  99. if diff.renamed_file
  100. "#{diff.a_path.rtruncate 50} => #{diff.b_path.rtruncate 50}"
  101. else
  102. filename.rtruncate(100)
  103. end
  104. end
  105. 1 protected
  106. 1 def commits_pluralization_arr
  107. pluralize ||= t('layout.commits.pluralize').map {|base, title| title.to_s}
  108. end
  109. 1 def render_file_changes(options = {})
  110. diff = options[:diff]
  111. adds = options[:adds]
  112. deletes = options[:deletes]
  113. total = options[:total]
  114. repo = options[:repo]
  115. file_status = options[:file_status]
  116. commit_id = get_commit_id_for_file(diff, options[:commit], options[:parent_commit])
  117. blob = file_blob_in_diff(repo, commit_id, diff)
  118. res = ''
  119. res << "<div class='col-sm-3'>"
  120. res << "<div class='pull-right'>"
  121. if blob.binary?
  122. res << "<strong class='text-primary'>#{t 'layout.projects.diff.binary'} #{file_status}</strong>"
  123. elsif total > 0
  124. res << "<strong class='text-success'>+#{adds}</strong> <strong class='text-danger'>-#{deletes}</strong>"
  125. else # total == 0
  126. res << "<strong class='text-primary'>#{t 'layout.projects.diff.without_changes'}</strong>"
  127. end
  128. res << "</div>"
  129. res << "</div>"
  130. res << "<div class='col-sm-1'>"
  131. res << render_progress_bar(adds, deletes, total, blob)
  132. res << "</div>"
  133. end
  134. 1 def render_progress_bar(adds, deletes, total, blob)
  135. res = ''
  136. pluses = 0
  137. minuses = 0
  138. if total > 0
  139. pluses = ((adds/(adds+deletes).to_f)*100).round
  140. minuses = 100 - pluses
  141. end
  142. title = if total >0
  143. t 'layout.projects.inline_changes_count', count: total
  144. elsif !blob.binary?
  145. t 'layout.projects.diff.without_changes'
  146. else
  147. 'BIN'
  148. end
  149. res << "<div class='progress' style='margin-bottom: 0' data-toggle='tooltip' data-placement='top' title='#{title}'>"
  150. res << "<div class='progress-bar progress-bar-success' style='width: #{pluses}%'></div>"
  151. res << "<div class='progress-bar progress-bar-danger' style='width: #{minuses}%'></div>"
  152. res << "</div>"
  153. res
  154. end
  155. 1 def diff_file_icon(diff)
  156. icon = case get_file_status_in_diff(diff)
  157. when :renamed_file
  158. 'fa-caret-square-o-right text-info'
  159. when :new_file
  160. 'fa-plus-square text-success'
  161. when :deleted_file
  162. 'fa-minus-square text-danger'
  163. when :changed_file
  164. 'fa-pencil-square text-primary'
  165. else
  166. 'fa-exclamation-circle text-danger'
  167. end
  168. "<i class='fa #{icon}'></i>"
  169. end
  170. end

app/helpers/datatable_helper.rb

57.14% lines covered

7 relevant lines. 4 lines covered and 3 lines missed.
    
  1. 1 module DatatableHelper
  2. 1 def page
  3. (params[:iDisplayStart].to_i/(params[:iDisplayLength].present? ? params[:iDisplayLength] : 25).to_i).to_i + 1
  4. end
  5. 1 def per_page
  6. params[:iDisplayLength].present? ? params[:iDisplayLength] : 25
  7. end
  8. 1 def sort_dir
  9. params[:sSortDir_0] == 'asc' ? 'asc' : 'desc'
  10. end
  11. end

app/helpers/devise_helper.rb

30.0% lines covered

10 relevant lines. 3 lines covered and 7 lines missed.
    
  1. 1 module DeviseHelper
  2. 1 def getDeviseErrors(*name)
  3. res = Array.new(name.count)
  4. resource.errors.each do |attr, message|
  5. if index = name.index(attr)
  6. res[index] = message
  7. end
  8. end
  9. res
  10. end
  11. 1 def showDeviseHintError(name, error, additional_class = '')
  12. if error
  13. "<div id='hint' class='error #{name.to_s} #{additional_class}' style='display: block;'> \
  14. <div class='img'></div> \
  15. <div class='msg'> #{error}</div> \
  16. </div>".html_safe
  17. end
  18. end
  19. end

app/helpers/diff_helper.rb

25.95% lines covered

158 relevant lines. 41 lines covered and 117 lines missed.
    
  1. 1 module DiffHelper
  2. 1 include CommitHelper
  3. 1 MAX_LINES_WITHOUT_COLLAPSE = 50
  4. 1 def render_diff_stats(options = {})
  5. stats = options[:stats]
  6. diff = options[:diff]
  7. repo = options[:repo]
  8. commit = options[:commit]
  9. parent_commit = options[:common_ancestor]
  10. res = ["<ul class='list-group boffset0'>"]
  11. stats.each_with_index do |stat, ind|
  12. adds = stat.additions
  13. deletes = stat.deletions
  14. total = adds + deletes
  15. file_name = get_filename_in_diff(diff[ind], stat.filename)
  16. file_status = t "layout.projects.diff.#{get_file_status_in_diff(diff[ind])}"
  17. res << "<li class='list-group-item'>"
  18. res << "<div class='row'>"
  19. res << "<div class='col-sm-8'>"
  20. res << "<a href='#diff-#{ind}' data-toggle='tooltip' data-placement='top' title='#{file_status}'>"
  21. res << "#{diff_file_icon(diff[ind])} #{h(file_name)}"
  22. res << "</a></div>"
  23. res << render_file_changes(diff: diff[ind], adds: adds, deletes: deletes, total: total,
  24. repo: repo, commit: commit, parent_commit: parent_commit, file_status: file_status)
  25. res << "</div"
  26. res << "</li>"
  27. ind +=1
  28. end
  29. res << "</ul>"
  30. wrap_diff_header_list(stats, res)
  31. end
  32. 1 def wrap_diff_header_list(stats, list)
  33. is_stats_open = stats.count <= MAX_FILES_WITHOUT_COLLAPSE ? 'in' : ''
  34. res = ["<div class='panel-group' id='diff_header' role='tablist' aria-multiselectable='false'>"]
  35. res << "<div class='panel panel-default'>"
  36. res << "<div class='panel-heading' role='tab' id='heading'>"
  37. res << "<h4 class='panel-title'>"
  38. res << "<a data-toggle='collapse' data-parent='#diff_header' href='#collapseList' aria-expanded='true' aria-controls='collapseList'>"
  39. res << "<span class='fa fa-chevron-#{is_stats_open ? 'down' : 'up'}'></span>"
  40. res << " #{diff_header_message(stats)}</a>"
  41. res << "</h4>"
  42. res << "</div>"
  43. res << "<div id='collapseList' class='panel-collapse collapse #{is_stats_open}' role='tabpanel' aria-labelledby='collapseList'>"
  44. res << "<div class='panel-body'>"
  45. res += list
  46. res << "</div>"
  47. res << "</div>"
  48. res << "</div>"
  49. res << "</div>"
  50. res.join("\n").html_safe
  51. end
  52. 1 def diff_header_message(stats)
  53. total_additions = stats.inject(0) {|sum, n| sum + n.additions}
  54. total_deletions = stats.inject(0) {|sum, n| sum + n.deletions}
  55. I18n.t('layout.projects.diff_show_header',
  56. files: t('layout.projects.commit_files_count', count: stats.count),
  57. additions: t('layout.projects.commit_additions_count', count: total_additions),
  58. deletions: t('layout.projects.commit_deletions_count', count: total_deletions))
  59. end
  60. #include Git::Diff::InlineCallback
  61. 1 def render_diff(diff, args = {})#diff_counter, comments, opts = nil diffpath = nil)
  62. if diff.respond_to?(:diff)
  63. diff, filepath, in_discussion = diff.diff, diff.a_path, false
  64. comments = (args[:comments] || []).select{|c| c.data.try('[]', :path) == filepath}
  65. else
  66. filepath, in_discussion, comments = args[:diffpath], true, args[:comments]
  67. end
  68. diff_display ||= Diff::Display::Unified.new(diff)
  69. url = if @pull
  70. @pull.id ? polymorphic_path([@project, @pull]) : ''
  71. elsif @commit
  72. commit_path @project, @commit
  73. end
  74. prepare(args.merge({filepath: filepath, comments: comments, in_discussion: in_discussion}))
  75. res = '<div class="table-responsive overflow-auto">'
  76. res << '<table class="table diff inline table-borderless" cellspacing="0" cellpadding="0">'
  77. res << '<tbody>'
  78. res << renderer(diff_display.data) #diff_display.render(Git::Diff::InlineCallback.new comments, path)
  79. res << tr_line_comments(comments) if in_discussion
  80. res << '</tbody>'
  81. res << '</table>'
  82. res << '</div>'
  83. res.html_safe
  84. end
  85. ########################################################
  86. # FIXME: Just to dev, remove to lib. Really need it?
  87. ########################################################
  88. 1 def prepare(args)
  89. @url, @diff_counter, @in_discussion = args[:url], args[:diff_counter], args[:in_discussion]
  90. @filepath, @line_comments = args[:filepath], args[:comments]
  91. @diff_prefix = args[:diff_prefix] || 'diff'
  92. @add_reply_id, @num_line = if @in_discussion
  93. [@line_comments[0].id, @line_comments[0].data[:line].to_i - @line_comments[0].data[:strings].lines.count.to_i-1]
  94. else
  95. [nil, -1]
  96. end
  97. @no_commit_comment = true if params[:controller] == 'projects/wiki' || (params[:action] == 'diff')
  98. end
  99. 1 def headerline(line)
  100. set_line_number
  101. "<tr class='header'>
  102. <td class='line_numbers'>...</td>
  103. <td class='line_numbers'>...</td>
  104. <td class='header'>#{line}</td>
  105. </tr>"
  106. end
  107. 1 def addline(line)
  108. set_line_number
  109. "<tr class='changes'>
  110. <td class='line_numbers'></td>
  111. #{td_line_link "#{@diff_prefix}-F#{@diff_counter}R#{line.new_number}", line.new_number}
  112. <td class='code ins'>
  113. #{line_comment_icon}
  114. <pre ng-non-bindable>#{render_line(line)}</pre>
  115. </td>
  116. </tr>
  117. #{render_line_comments}"
  118. end
  119. 1 def remline(line)
  120. set_line_number
  121. "<tr class='changes'>
  122. #{td_line_link "#{@diff_prefix}-F#{@diff_counter}L#{line.old_number}", line.old_number}
  123. <td class='line_numbers'></td>
  124. <td class='code del'>
  125. #{line_comment_icon}
  126. <pre ng-non-bindable>#{render_line(line)}</pre>
  127. </td>
  128. </tr>
  129. #{render_line_comments}"
  130. end
  131. 1 def modline(line)
  132. set_line_number
  133. "<tr class='changes line'>
  134. #{td_line_link "#{@diff_prefix}-F#{@diff_counter}L#{line.old_number}", line.old_number}
  135. #{td_line_link "#{@diff_prefix}-F#{@diff_counter}R#{line.new_number}", line.new_number}
  136. <td class='code unchanged modline'>
  137. #{line_comment_icon}
  138. <pre ng-non-bindable>#{render_line(line)}</pre>
  139. </td>
  140. </tr>
  141. #{render_line_comments}"
  142. end
  143. 1 def unmodline(line)
  144. set_line_number
  145. "<tr class='changes unmodline'>
  146. #{td_line_link "#{@diff_prefix}-F#{@diff_counter}L#{line.old_number}", line.old_number}
  147. #{td_line_link "#{@diff_prefix}-F#{@diff_counter}R#{line.new_number}", line.new_number}
  148. <td class='code unchanged unmodline'>
  149. #{line_comment_icon}
  150. <pre ng-non-bindable>#{render_line(line)}</pre>
  151. </td>
  152. </tr>
  153. #{render_line_comments}"
  154. end
  155. 1 def sepline(line)
  156. "<tr class='changes hunk-sep'>
  157. <td class='line_numbers line_num_cut'>&hellip;</td>
  158. <td class='line_numbers line_num_cut'>&hellip;</td>
  159. <td class='code cut-line'></td>
  160. </tr>"
  161. end
  162. 1 def nonewlineline(line)
  163. set_line_number
  164. "<tr class='changes'>
  165. #{td_line_link "#{@diff_prefix}-F#{@diff_counter}L#{line.old_number}", line.old_number}
  166. #{td_line_link "#{@diff_prefix}-F#{@diff_counter}R#{line.new_number}", line.new_number}
  167. <td class='code modline unmodline'>
  168. #{line_comment_icon}
  169. <pre ng-non-bindable>#{render_line(line)}</pre>
  170. </td>
  171. </tr>
  172. #{render_line_comments}"
  173. end
  174. 1 def before_headerblock(block)
  175. end
  176. 1 def after_headerblock(block)
  177. end
  178. 1 def before_unmodblock(block)
  179. end
  180. 1 def before_modblock(block)
  181. end
  182. 1 def before_remblock(block)
  183. end
  184. 1 def before_addblock(block)
  185. end
  186. 1 def before_sepblock(block)
  187. end
  188. 1 def before_nonewlineblock(block)
  189. end
  190. 1 def after_unmodblock(block)
  191. end
  192. 1 def after_modblock(block)
  193. end
  194. 1 def after_remblock(block)
  195. end
  196. 1 def after_addblock(block)
  197. end
  198. 1 def after_sepblock(block)
  199. end
  200. 1 def after_nonewlineblock(block)
  201. end
  202. 1 def new_line
  203. ""
  204. end
  205. 1 def renderer(data)
  206. result = []
  207. data.each do |block|
  208. result << send("before_" + classify(block), block)
  209. result << block.map { |line| send(classify(line), line) }
  210. result << send("after_" + classify(block), block)
  211. end
  212. result.compact.join(new_line)
  213. end
  214. 1 protected
  215. 1 def classify(object)
  216. object.class.name[/\w+$/].downcase
  217. end
  218. 1 def escape(str)
  219. str.to_s.gsub('&', '&amp;').gsub('<', '&lt;').gsub('>', '&gt;').gsub('"', '&#34;')
  220. end
  221. 1 def render_line(line)
  222. res = '<span class="diff-content">'
  223. if line.inline_changes?
  224. prefix, changed, postfix = line.segments.map{|segment| escape(segment) }
  225. res << "#{prefix}<span class='idiff'>#{changed}</span>#{postfix}"
  226. else
  227. res << escape(line)
  228. end
  229. res << '</span>'
  230. res
  231. end
  232. 1 def set_line_number
  233. @num_line = @num_line.succ
  234. end
  235. 1 def line_comment_icon
  236. return if @no_commit_comment || (@in_discussion && @add_reply_id && @line_comments[0].data[:line].to_i != @num_line)
  237. if current_user
  238. link_to image_tag('line_comment.png', alt: t('layout.comments.new_header')),
  239. '#new_inline_comment',
  240. class: 'add_line-comment',
  241. 'ng-click' => "commentsCtrl.showInlineForm($event, #{new_inline_comment_params.to_json})"
  242. end
  243. end
  244. 1 def render_line_comments
  245. unless @no_commit_comment || @in_discussion
  246. comments = @line_comments.select do |c|
  247. c.data.try('[]', :line).to_s == @num_line.to_s && c.actual_inline_comment?
  248. end
  249. tr_line_comments(comments) if comments.count > 0
  250. end
  251. end
  252. 1 def td_line_link id, num
  253. "<td class='line_numbers' id='#{id}'><a href='#{@url}##{id}'>#{num}</a></td>"
  254. end
  255. 1 def tr_line_comments comments
  256. return if @no_commit_comment
  257. res="<tr class='line-comments'>
  258. <td class='line_numbers' colspan='2'>#{comments.count}</td>
  259. <td>"
  260. comments.each do |comment|
  261. res << "<div class='line-comment'>
  262. #{render 'projects/comments/comment', comment: comment, data: {project: @project, commentable: @commentable, add_anchor: 'inline', in_discussion: @in_discussion}}
  263. </div>"
  264. end
  265. if current_user
  266. res << link_to( t('layout.comments.new_inline'),
  267. '#new_inline_comment',
  268. class: 'btn btn-primary',
  269. 'ng-click' => "commentsCtrl.showInlineForm($event, #{new_inline_comment_params.to_json})",
  270. 'ng-hide' => "commentsCtrl.hideInlineCommentButton(#{new_inline_comment_params.to_json})" )
  271. end
  272. res << "</td></tr>"
  273. end
  274. # def new_comment_path
  275. # hash = {path: @filepath, line: @num_line}
  276. # if @commentable.is_a? Issue
  277. # project_new_line_pull_comment_path(@project, @commentable, hash.merge({in_reply: @add_reply_id}))
  278. # elsif @commentable.is_a? Grit::Commit
  279. # new_line_commit_comment_path(@project, @commentable, hash)
  280. # end
  281. # end
  282. 1 def new_inline_comment_params
  283. { path: @filepath, line: @num_line, in_reply: @add_reply_id }
  284. end
  285. end

app/helpers/file_store_helper.rb

33.33% lines covered

9 relevant lines. 3 lines covered and 6 lines missed.
    
  1. 1 module FileStoreHelper
  2. 1 def file_store_results_url(sha1, file_name)
  3. url = "#{APP_CONFIG['file_store_url']}/api/v1/file_stores/#{sha1}"
  4. url << '.log?show=true' if file_name =~ /.*\.(log|txt)$/ || file_name =~ /.*\.(log.gz|txt.gz)/
  5. url
  6. end
  7. 1 def link_to_file_store(file_name, sha1)
  8. if sha1.present?
  9. link_to file_name, file_store_results_url(sha1, file_name)
  10. else
  11. I18n.t('layout.no_')
  12. end
  13. end
  14. end

app/helpers/git_helper.rb

11.65% lines covered

103 relevant lines. 12 lines covered and 91 lines missed.
    
  1. 1 module GitHelper
  2. 1 def submodule_url(node, treeish)
  3. # node.url(treeish) looks like:
  4. # - http://0.0.0.0:3000/abf/git@abf.rosalinux.ru:abf/rhel-scripts.git
  5. # - git://github.com/avokhmin/mdv-scripts.git
  6. # - empty string if ".gitmodules" does not exist
  7. url = node.url(treeish)
  8. return nil if url.blank?
  9. url.gsub!(/.git$/, '')
  10. if url =~ /^git:/
  11. url.gsub!(/^git/, 'http')
  12. elsif str = /git@.*:.*/.match(url)
  13. str = str[0].gsub(/^git@/, '')
  14. domen = str.gsub(/:.*/, '')
  15. owner = str.gsub(/^#{domen}:/, '').gsub(/\/.*/, '')
  16. project = str.gsub(/.*\//, '')
  17. url = "http://#{domen}/#{owner}/#{project}"
  18. end
  19. url
  20. end
  21. 1 def render_path
  22. # TODO: Looks ugly, rewrite with clear mind.
  23. if @path.present?
  24. if @treeish == @project.resolve_default_branch
  25. res = "#{link_to @project.name, tree_path(@project)} / "
  26. else
  27. res = "#{link_to @project.name, tree_path(@project, @treeish)} / "
  28. end
  29. parts = @path.split("/")
  30. current_path = parts.first
  31. res << (parts.length == 1 ? parts.first : link_to(parts.first, tree_path(@project, @treeish, current_path)) + " / ")
  32. parts[1..-2].each do |part|
  33. current_path = File.join([current_path, part].compact)
  34. res << link_to(part, tree_path(@project, @treeish, current_path))
  35. res << " / "
  36. end
  37. res << parts.last if parts.length > 1
  38. else
  39. res = "#{link_to @project.name, tree_path(@project)} /"
  40. end
  41. res.html_safe
  42. end
  43. 1 def render_line_numbers(n)
  44. res = ""
  45. 1.upto(n){ |i| res << "<span id='L#{i}'><a href='#L#{i}'>#{i}</a></span><br/>" }
  46. res.html_safe
  47. end
  48. 1 def iterate_path(path)
  49. tree = []
  50. path.split("\/").each do |name|
  51. if tree.last
  52. tree << [File.join(tree.try(:last).try(:first), name), name]
  53. else
  54. tree << [name, name]
  55. end
  56. end
  57. tree
  58. end
  59. 1 def branch_selector_options(project)
  60. p, tag_enabled = params.dup.to_unsafe_h, !(controller_name == 'trees' && action_name == 'branches')
  61. p.delete(:path) if p[:path].present? # to root path
  62. p.merge!(project_id: project.id, treeish: project.resolve_default_branch).delete(:id) unless p[:treeish].present?
  63. current = url_for(p).split('?', 2).first
  64. res = []
  65. if params[:treeish].present? && !project.repo.branches_and_tags.map(&:name).include?(params[:treeish])
  66. res << [I18n.t('layout.git.repositories.commits'), [params[:treeish].truncate(20)]]
  67. end
  68. linking = Proc.new {|name| [name.truncate(20), url_for(p.merge treeish: name).split('?', 2).first]}
  69. res << [I18n.t('layout.git.repositories.branches'), project.repo.branches.map(&:name).sort.map(&linking)]
  70. if tag_enabled
  71. res << [I18n.t('layout.git.repositories.tags'), project.repo.tags.map(&:name).sort.map(&linking)]
  72. else
  73. res << [I18n.t('layout.git.repositories.tags'), project.repo.tags.map(&:name).sort.map {|name| [name.truncate(20), {disabled: true}]}]
  74. end
  75. grouped_options_for_select(res, current)
  76. end
  77. 1 def versions_for_group_select(project)
  78. return [] unless project
  79. [
  80. [I18n.t('layout.git.repositories.branches'), project.repo.branches.map(&:name).sort],
  81. [I18n.t('layout.git.repositories.tags'), project.repo.tags.map(&:name).sort]
  82. ]
  83. end
  84. 1 def split_commits_by_date(commits)
  85. commits.inject({}) do |h, commit|
  86. dt = commit.committed_date
  87. h[dt.year] ||= {}
  88. h[dt.year][dt.month] ||= {}
  89. h[dt.year][dt.month][dt.day] ||= []
  90. h[dt.year][dt.month][dt.day] << commit
  91. h
  92. end
  93. end
  94. 1 def blob_highlight(blob, path)
  95. return if blob.nil? || blob.size == 0
  96. rugged = blob.repo.rugged
  97. lazy = Linguist::LazyBlob.new(rugged, blob.id, path, blob.mode)
  98. language = lazy.language
  99. lexer = nil
  100. if language
  101. lexer = Pygments::Lexer.find_by_name(language.name)
  102. if !lexer
  103. language.aliases.each do |al|
  104. lexer = Pygments::Lexer.find_by_alias(al)
  105. break if lexer
  106. end
  107. end
  108. lexer = Pygments::Lexer.find('spec') if language.name == 'RPM Spec'
  109. end
  110. lexer = Pygments::Lexer.find('Text') if !lexer
  111. result = lexer.highlight rugged.lookup(blob.id).text, highlight_options
  112. result.present? ? result.html_safe : text
  113. rescue => e
  114. "<pre>#{blob.data}</pre>".html_safe
  115. end
  116. 1 def blame_highlight(blob, path, text)
  117. return if blob.nil? || text.blank?
  118. rugged = blob.repo.rugged
  119. lazy = Linguist::LazyBlob.new(rugged, blob.id, path, blob.mode)
  120. language = lazy.language
  121. lexer = nil
  122. if language
  123. lexer = Pygments::Lexer.find_by_name(language.name)
  124. if !lexer
  125. language.aliases.each do |al|
  126. lexer = Pygments::Lexer.find_by_alias(al)
  127. break if lexer
  128. end
  129. end
  130. lexer = Pygments::Lexer.find('spec') if language.name == 'RPM Spec'
  131. end
  132. lexer = Pygments::Lexer.find('Text') if !lexer
  133. result = lexer.highlight(text)
  134. result.present? ? result.html_safe : text
  135. rescue => e
  136. puts e
  137. "<pre>#{text}</pre>".html_safe
  138. end
  139. 1 protected
  140. 1 def highlight_options
  141. @highlight ||= { options: { linenos: true, lineanchors: 'lc', linespans: 'ln', anchorlinenos: true }}
  142. end
  143. end

app/helpers/gitlab_markdown_helper.rb

25.58% lines covered

43 relevant lines. 11 lines covered and 32 lines missed.
    
  1. # This module is based on
  2. # https://github.com/gitlabhq/gitlabhq/blob/7665b1de7eed4addd7b94786c84e6674710e6377/app/helpers/gitlab_markdown_helper.rb
  3. 1 module GitlabMarkdownHelper
  4. 1 include MarkdownHelper
  5. # Use this in places where you would normally use link_to(gfm(...), ...).
  6. #
  7. # It solves a problem occurring with nested links (i.e.
  8. # "<a>outer text <a>gfm ref</a> more outer text</a>"). This will not be
  9. # interpreted as intended. Browsers will parse something like
  10. # "<a>outer text </a><a>gfm ref</a> more outer text" (notice the last part is
  11. # not linked any more). link_to_gfm corrects that. It wraps all parts to
  12. # explicitly produce the correct linking behavior (i.e.
  13. # "<a>outer text </a><a>gfm ref</a><a> more outer text</a>").
  14. 1 def link_to_gfm(body, url, html_options = {})
  15. return "" if body.blank?
  16. escaped_body = if body =~ /^\<img/
  17. body
  18. else
  19. escape_once(body)
  20. end
  21. gfm_body = gfm(escaped_body, html_options)
  22. gfm_body.gsub!(%r{<a.*?>.*?</a>}m) do |match|
  23. "</a>#{match}#{link_to("", url, html_options)[0..-5]}" # "</a>".length +1
  24. end
  25. link_to(gfm_body.html_safe, url, html_options)
  26. end
  27. 1 def markdown(text)
  28. return '' if text.blank?
  29. unless @markdown
  30. gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self,
  31. # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch-
  32. filter_html: true,
  33. with_toc_data: true,
  34. hard_wrap: true)
  35. @markdown = Redcarpet::Markdown.new(gitlab_renderer,
  36. # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
  37. no_intra_emphasis: true,
  38. tables: true,
  39. fenced_code_blocks: true,
  40. autolink: true,
  41. strikethrough: true,
  42. lax_html_blocks: true,
  43. space_after_headers: true,
  44. superscript: true)
  45. end
  46. @markdown.render(text).html_safe
  47. end
  48. 1 def create_relative_links(text)
  49. paths = extract_paths(text)
  50. paths.uniq.each do |file_path|
  51. new_path = rebuild_path(file_path)
  52. # Finds quoted path so we don't replace other mentions of the string
  53. # eg. "doc/api" will be replaced and "/home/doc/api/text" won't
  54. text.gsub!("\"#{file_path}\"", "\"/#{new_path}\"")
  55. end
  56. text
  57. end
  58. 1 def extract_paths(text)
  59. links = substitute_links(text)
  60. image_links = substitute_image_links(text)
  61. links + image_links
  62. end
  63. 1 def substitute_links(text)
  64. links = text.scan(/<a href=\"([^"]*)\">/)
  65. relative_links = links.flatten.reject{ |link| link_to_ignore? link }
  66. relative_links
  67. end
  68. 1 def substitute_image_links(text)
  69. links = text.scan(/<img src=\"([^"]*)\"/)
  70. relative_links = links.flatten.reject{ |link| link_to_ignore? link }
  71. relative_links
  72. end
  73. 1 def link_to_ignore?(link)
  74. ignored_protocols.map{ |protocol| link.include?(protocol) }.any?
  75. end
  76. 1 def ignored_protocols
  77. ["http://","https://", "ftp://", "mailto:"]
  78. end
  79. 1 def render_wiki_content(wiki_page)
  80. if wiki_page.format == :markdown
  81. markdown(wiki_page.content)
  82. else
  83. wiki_page.formatted_content.html_safe
  84. end
  85. end
  86. end

app/helpers/hooks_helper.rb

100.0% lines covered

1 relevant lines. 1 lines covered and 0 lines missed.
    
  1. 1 module HooksHelper
  2. end

app/helpers/issues_helper.rb

33.33% lines covered

6 relevant lines. 2 lines covered and 4 lines missed.
    
  1. 1 module IssuesHelper
  2. 1 def tracker_search_field(name, txt, classes = nil)
  3. str = "<input name='#{name}' id='#{name}' type='text' value='#{txt}'"
  4. str << "onblur=\"if(this.value==''){this.value='#{txt}';this.className='gray #{classes}';}\""
  5. str << "onclick=\"if(this.value=='#{txt}'){this.value='';this.className='black #{classes}';}\" class=\"gray #{classes}\">"
  6. str.html_safe
  7. end
  8. end

app/helpers/key_pairs_helper.rb

50.0% lines covered

4 relevant lines. 2 lines covered and 2 lines missed.
    
  1. 1 module KeyPairsHelper
  2. 1 def key_pair_repository_options(platform)
  3. platform.repositories.map do |r|
  4. [r.name, r.id]
  5. end
  6. end
  7. end

app/helpers/markdown_helper.rb

25.0% lines covered

64 relevant lines. 16 lines covered and 48 lines missed.
    
  1. # This module is based on
  2. # https://github.com/gitlabhq/gitlabhq/blob/397c3da9758c03a215a308c011f94261d9c61cfa/lib/gitlab/markdown.rb
  3. # Custom parser for GitLab-flavored Markdown
  4. #
  5. # It replaces references in the text with links to the appropriate items in
  6. # GitLab.
  7. #
  8. # Supported reference formats are:
  9. # * @foo for team members
  10. # * for issues & pull requests:
  11. # * #123
  12. # * abf#123
  13. # * abf/rosa-build#123
  14. # * 123456 for commits
  15. #
  16. # It also parses Emoji codes to insert images. See
  17. # http://www.emoji-cheat-sheet.com/ for a list of the supported icons.
  18. #
  19. # Examples
  20. #
  21. # >> gfm("Hey @david, can you fix this?")
  22. # => "Hey <a href="/users/david">@david</a>, can you fix this?"
  23. #
  24. # >> gfm("Commit 35d5f7c closes #1234")
  25. # => "Commit <a href="/gitlab/commits/35d5f7c">35d5f7c</a> closes <a href="/gitlab/issues/1234">#1234</a>"
  26. #
  27. # >> gfm(":trollface:")
  28. # => "<img alt=\":trollface:\" class=\"emoji\" src=\"/images/trollface.png" title=\":trollface:\" />
  29. 1 module MarkdownHelper
  30. 1 include IssuesHelper
  31. 1 attr_reader :html_options
  32. # Public: Parse the provided text with GitLab-Flavored Markdown
  33. #
  34. # text - the source text
  35. # html_options - extra options for the reference links as given to link_to
  36. #
  37. # Note: reference links will only be generated if @project is set
  38. 1 def gfm(text, html_options = {})
  39. return text if text.nil?
  40. # Duplicate the string so we don't alter the original, then call to_str
  41. # to cast it back to a String instead of a SafeBuffer. This is required
  42. # for gsub calls to work as we need them to.
  43. text = text.dup.to_str
  44. @html_options = html_options
  45. # Extract pre blocks so they are not altered
  46. # from http://github.github.com/github-flavored-markdown/
  47. text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) { |match| extract_piece(match) }
  48. # Extract links with probably parsable hrefs
  49. text.gsub!(%r{<a.*?>.*?</a>}m) { |match| extract_piece(match) }
  50. # Extract images with probably parsable src
  51. text.gsub!(%r{<img.*?>}m) { |match| extract_piece(match) }
  52. # TODO: add popups with additional information
  53. text = parse(text)
  54. # Insert pre block extractions
  55. text.gsub!(/\{gfm-extraction-(\h{32})\}/) do
  56. insert_piece($1)
  57. end
  58. sanitize text.html_safe, attributes: %w(href src alt id class)
  59. end
  60. 1 private
  61. 1 def extract_piece(text)
  62. @extractions ||= {}
  63. md5 = Digest::MD5.hexdigest(text)
  64. @extractions[md5] = text
  65. "{gfm-extraction-#{md5}}"
  66. end
  67. 1 def insert_piece(id)
  68. @extractions[id]
  69. end
  70. # Private: Parses text for references and emoji
  71. #
  72. # text - Text to parse
  73. #
  74. # Note: reference links will only be generated if @project is set
  75. #
  76. # Returns parsed text
  77. 1 def parse(text)
  78. parse_references(text) if @project
  79. parse_emoji(text)
  80. end
  81. 1 REFERENCE_PATTERN = %r{
  82. (?<prefix>[\W\/])? # Prefix
  83. ( # Reference
  84. @(?<user>[a-zA-Z][a-zA-Z0-9_\-\.]*) # User/Group uname
  85. |(?<issue>(?:[a-zA-Z0-9\-_]*\/)?(?:[a-zA-Z0-9\-_]*)?\#[0-9]+) # Issue ID
  86. |(?<commit>[\h]{6,40}) # Commit ID
  87. )
  88. (?<suffix>\W)? # Suffix
  89. }x.freeze
  90. 1 TYPES = [:user, :issue, :commit].freeze
  91. 1 def parse_references(text)
  92. # parse reference links
  93. text.gsub!(REFERENCE_PATTERN) do |match|
  94. prefix = $~[:prefix]
  95. suffix = $~[:suffix]
  96. type = TYPES.select{|t| !$~[t].nil?}.first
  97. identifier = $~[type]
  98. # Avoid HTML entities
  99. if prefix && suffix && prefix[0] == '&' && suffix[-1] == ';'
  100. match
  101. elsif ref_link = reference_link(type, identifier)
  102. "#{prefix}#{ref_link}#{suffix}"
  103. else
  104. match
  105. end
  106. end
  107. end
  108. 1 def parse_emoji(text)
  109. text.gsub(/:([\w+-]+):/) do |match|
  110. if emoji = Emoji.find_by_alias($1)
  111. image_tag("/images/emoji/#{emoji.image_filename}", class: 'emoji', title: $1, alt: $1, size: "20x20")
  112. else
  113. match
  114. end
  115. end if text.present?
  116. end
  117. # Private: Dispatches to a dedicated processing method based on reference
  118. #
  119. # reference - Object reference ("@1234", "!567", etc.)
  120. # identifier - Object identifier (Issue ID, SHA hash, etc.)
  121. #
  122. # Returns string rendered by the processing method
  123. 1 def reference_link(type, identifier)
  124. send("reference_#{type}", identifier)
  125. end
  126. 1 def reference_user(identifier)
  127. member = User.where(uname: identifier).first || Group.where(uname: identifier).first
  128. if member
  129. link_to("@#{identifier}", "/#{identifier}", html_options.merge(title: member.fullname, class: "gfm gfm-member #{html_options[:class]}"))
  130. end
  131. end
  132. 1 def reference_issue(identifier)
  133. if issue = Issue.find_by_hash_tag(identifier, current_user, @project)
  134. if issue.pull_request
  135. title = "#{PullRequest.model_name.human}: #{issue.title}"
  136. url = project_pull_request_path(issue.project, issue.pull_request)
  137. else
  138. title = "#{Issue.model_name.human}: #{issue.title}"
  139. url = project_issue_path(issue.project, issue.serial_id)
  140. end
  141. link_to(identifier, url, html_options.merge(title: title, class: "gfm gfm-issue #{html_options[:class]}"))
  142. end
  143. end
  144. 1 def reference_commit(identifier)
  145. commit = @project.repo.commit(identifier) rescue nil
  146. if commit
  147. link_to shortest_hash_id(commit.id), commit_path(@project, commit.id)
  148. title = GitPresenters::CommitAsMessagePresenter.present(commit, project: @project) do |presenter|
  149. link_to(identifier, commit_path(@project, commit), html_options.merge(title: presenter.caption, class: "gfm gfm-commit #{html_options[:class]}"))
  150. end
  151. end
  152. end
  153. end

app/helpers/mass_build_helper.rb

40.0% lines covered

10 relevant lines. 4 lines covered and 6 lines missed.
    
  1. 1 module MassBuildHelper
  2. 1 def link_to_list platform, mass_build, which
  3. link_to t("layout.mass_builds.#{which}"),
  4. get_list_platform_mass_build_path(platform, mass_build, kind: which, format: :txt),
  5. target: "_blank" if policy(mass_build).get_list?
  6. end
  7. 1 def link_to_mass_build(mass_build)
  8. link_to mass_build.name, build_lists_path+"#?#{{filter: {mass_build_id: mass_build.id, ownership: 'everything'}}.to_param}"
  9. end
  10. 1 def new_mass_build_data(mass_build, platform, params)
  11. {
  12. platform_id: mass_build.save_to_platform.try(:id),
  13. repositories: platform.repositories.map do |repo|
  14. { id: repo.id,
  15. name: repo.name,
  16. checked: (params[:repositories]||[]).include?(repo.id.to_s) }
  17. end
  18. }.to_json
  19. end
  20. end

app/helpers/paginate_helper.rb

21.05% lines covered

19 relevant lines. 4 lines covered and 15 lines missed.
    
  1. 1 module PaginateHelper
  2. 1 def paginate_params
  3. per_page = params[:per_page].to_i
  4. per_page = 20 if per_page < 1
  5. per_page = 100 if per_page >100
  6. page = params[:page].to_i
  7. page = nil if page == 0
  8. {page: page, per_page: per_page}
  9. end
  10. 1 def will_paginate(collection_or_options = nil, options = {})
  11. if collection_or_options.is_a? Hash
  12. options, collection_or_options = collection_or_options, nil
  13. end
  14. options.merge!(renderer: BootstrapLinkRenderer) unless options[:renderer]
  15. options.merge!(next_label: I18n.t('datatables.next_label')) unless options[:next_label]
  16. options.merge!(previous_label: I18n.t('datatables.previous_label')) unless options[:previous_label]
  17. super *[collection_or_options, options].compact
  18. end
  19. 1 def angularjs_paginate(options = {})
  20. options.reverse_merge!(
  21. {
  22. per_page: params[:per_page].to_i > 0 ? params[:per_page] : 20,
  23. total_items: 'total_items',
  24. page: 'page',
  25. select_page: "goToPage(page)"
  26. }
  27. )
  28. render 'shared/angularjs_paginate', options
  29. end
  30. end

app/helpers/platforms_helper.rb

28.0% lines covered

25 relevant lines. 7 lines covered and 18 lines missed.
    
  1. 1 module PlatformsHelper
  2. 1 def platform_options
  3. Platform.main.each do |p|
  4. [ p.name, p.id ]
  5. end
  6. end
  7. 1 def platform_visibility_options
  8. Platform::VISIBILITIES.map do |v|
  9. [ I18n.t("activerecord.attributes.platform.visibility_types.#{v}"), v ]
  10. end
  11. end
  12. 1 def repository_name_postfix(platform)
  13. return "" unless platform
  14. return platform.released ? '/update' : '/release'
  15. end
  16. 1 def platform_printed_name(platform)
  17. return "" unless platform
  18. platform.released? ? "#{platform.name} #{I18n.t("layout.platforms.released_suffix")}" : platform.name
  19. end
  20. 1 def platform_arch_settings(platform)
  21. settings = platform.platform_arch_settings
  22. arches = if (arch_ids = settings.map(&:arch_id)) && arch_ids.present?
  23. Arch.where('id not in (?)', arch_ids)
  24. else
  25. Arch.all
  26. end
  27. settings |= arches.map do |arch|
  28. platform.platform_arch_settings.build(
  29. :arch_id => arch.id,
  30. :time_living => PlatformArchSetting::DEFAULT_TIME_LIVING
  31. )
  32. end
  33. settings.sort_by{ |s| s.arch.name }
  34. end
  35. 1 def fa_platform_visibility_icon(platform)
  36. return nil unless platform
  37. image, color = platform.hidden? ? ['lock', 'text-danger fa-fw']: ['unlock-alt', 'text-success fa-fw']
  38. fa_icon(image, class: color)
  39. end
  40. end

app/helpers/product_build_lists_helper.rb

66.67% lines covered

3 relevant lines. 2 lines covered and 1 lines missed.
    
  1. 1 module ProductBuildListsHelper
  2. 1 def product_build_list_delete_options
  3. [false, true].map{ |status| [t("layout.#{status}_"), status] }
  4. end
  5. end

app/helpers/projects_helper.rb

28.3% lines covered

53 relevant lines. 15 lines covered and 38 lines missed.
    
  1. 1 module ProjectsHelper
  2. 1 def options_for_filters(all_projects, groups, owners)
  3. projects_count_by_groups = all_projects.where(owner_id: groups, owner_type: 'Group').
  4. group(:owner_id).count
  5. projects_count_by_owners = all_projects.where(owner_id: owners, owner_type: 'User').
  6. group(:owner_id).count
  7. (groups + owners).map do |o|
  8. class_name = o.class.name
  9. {
  10. class_name: class_name.downcase,
  11. id: o.id,
  12. uname: o.uname,
  13. count: o.is_a?(User) ? projects_count_by_owners[o.id] : projects_count_by_groups[o.id]
  14. }
  15. end.sort_by{ |f| f[:uname] }
  16. end
  17. 1 def available_project_to_repositories(project)
  18. project.project_to_repositories.includes(repository: :platform).select do |p_to_r|
  19. p_to_r.repository.publish_without_qa ? true : policy(p_to_r.repository.platform).local_admin_manage?
  20. end.sort_by do |p_to_r|
  21. "#{p_to_r.repository.platform.name}/#{p_to_r.repository.name}"
  22. end.map do |p_to_r|
  23. {
  24. repository_name: "#{p_to_r.repository.platform.name}/#{p_to_r.repository.name}",
  25. repository_path: platform_repository_path(p_to_r.repository.platform, p_to_r.repository),
  26. auto_publish: p_to_r.auto_publish?,
  27. enabled: p_to_r.enabled?,
  28. repository_id: p_to_r.repository_id
  29. }
  30. end.to_a.to_json
  31. end
  32. 1 def mass_import_repositories_for_group_select
  33. groups = {}
  34. PlatformPolicy::Scope.new(current_user, Platform).related.order(:name).each do |platform|
  35. next unless policy(platform).local_admin_manage?
  36. groups[platform.name] = Repository.custom_sort(platform.repositories).map{ |r| [r.name, r.id] }
  37. end
  38. groups.to_a
  39. end
  40. 1 def git_repo_url(name)
  41. if current_user
  42. "#{request.protocol}#{current_user.uname}@#{request.host_with_port}/#{name}.git"
  43. else
  44. "#{request.protocol}#{request.host_with_port}/#{name}.git"
  45. end
  46. end
  47. 1 def git_ssh_repo_url(name)
  48. "git@#{request.host}:#{name}.git"
  49. end
  50. 1 def options_for_collaborators_roles_select
  51. Relation::ROLES.map do |role|
  52. [t("layout.collaborators.role_names.#{ role }"), role]
  53. end
  54. end
  55. 1 def visibility_icon(visibility)
  56. visibility == 'open' ? 'unlock.png' : 'lock.png'
  57. end
  58. 1 def participant_class(alone_member, project)
  59. c = alone_member ? 'fa-user text-primary' : 'fa-group text-primary'
  60. c = 'fa-user text-success' if project.owner == current_user
  61. c = 'fa-group text-success' if project.owner.in? current_user.groups
  62. return c
  63. end
  64. 1 def alone_member?(project)
  65. Rails.cache.fetch(['ProjectsHelper#alone_member?', project, current_user]) do
  66. Relation.by_target(project).by_actor(current_user).exists?
  67. end
  68. end
  69. 1 def participant_path(participant)
  70. participant.kind_of?(User) ? user_path(participant) : group_path(participant)
  71. end
  72. 1 def fa_visibility_icon(project)
  73. return nil unless project
  74. image, color = project.public? ? ['unlock-alt', 'text-success fa-fw'] : ['lock', 'text-danger fa-fw']
  75. fa_icon(image, class: color)
  76. end
  77. 1 def project_ownership_options
  78. [
  79. [ I18n.t('activerecord.attributes.project.who_owns.me'), 'me' ],
  80. [ I18n.t('activerecord.attributes.project.who_owns.group'), 'group' ]
  81. ]
  82. end
  83. 1 def project_visibility_options
  84. Project::VISIBILITIES.map do |v|
  85. [ I18n.t("activerecord.attributes.project.visibilities.#{v}"), v ]
  86. end
  87. end
  88. 1 def project_owner_groups_options
  89. Group.can_own_project(current_user).map do |g|
  90. [ g.name, g.id ]
  91. end
  92. end
  93. end

app/helpers/pull_request_helper.rb

22.22% lines covered

36 relevant lines. 8 lines covered and 28 lines missed.
    
  1. 1 module PullRequestHelper
  2. 1 def merge_activity comments, commits
  3. common_comments, pull_comments = comments.partition {|c| c.automatic || c.data.blank?}
  4. common_comments = common_comments.map{ |c| [c.created_at, c] }
  5. pull_comments = pull_comments.group_by(&:data).map{|data, c| [c.first.created_at, [data || {}, [c].flatten]]}
  6. commits = commits.map{ |c| [(c.committed_date || c.authored_date), c] }
  7. (common_comments + pull_comments + commits).sort_by{ |c| c[0] }.map{ |c| c[1] }
  8. end
  9. 1 def pull_status_label pull_status, options = {}
  10. statuses = {'ready' => 'success', 'closed' => 'default', 'merged' => 'info', 'blocked' => 'warning'}
  11. options[:class] = "#{options[:class]} label label-#{statuses[pull_status]}"
  12. content_tag :span, t("projects.pull_requests.statuses.#{pull_status}"), options
  13. end
  14. 1 def pull_status pull
  15. if %w(blocked merged closed ready open).include? pull.status
  16. t("projects.pull_requests.#{pull.status}", user: pull.issue.closer.try(:uname), to_ref: show_ref(pull, 'to'),
  17. from_ref: show_ref(pull, 'from'), time: pull.issue.closed_at).html_safe
  18. else
  19. raise "pull id (#{pull.id}) wrong status #{pull.status} "
  20. end
  21. end
  22. 1 def pull_header pull
  23. str = "#{t '.header'} #{t 'from'} \
  24. #{show_ref pull, 'from'} \
  25. #{t 'into'} \
  26. #{show_ref pull, 'to'}"
  27. str << " #{t 'by'} #{link_to pull.user.uname, user_path(pull.user)}" if pull.user# pull.persisted?
  28. str.html_safe
  29. end
  30. #helper for helpers
  31. 1 def show_ref pull, which, limit = 30
  32. project, ref = pull.send("#{which}_project"), pull.send("#{which}_ref")
  33. fullname = if which == 'to'
  34. "#{project.owner.uname.truncate limit}/#{project.name.truncate limit}"
  35. elsif which == 'from'
  36. "#{pull.from_project_owner_uname.truncate limit}/#{pull.from_project_name.truncate limit}"
  37. end
  38. link_to "#{fullname}: #{ref.truncate limit}", ref_path(project, ref), class: 'btn btn-primary'
  39. end
  40. 1 def ref_path project, ref
  41. if project && project.repo.branches_and_tags.map(&:name).include?(ref)
  42. tree_path(project, ref)
  43. else
  44. '#'
  45. end
  46. end
  47. 1 def ref_selector_options(project, current)
  48. res = []
  49. value = Proc.new {|t| [t.name.truncate(50), t.name]}
  50. res << [I18n.t('layout.git.repositories.branches'), project.repo.branches.map(&value).sort]
  51. res << [I18n.t('layout.git.repositories.tags'), project.repo.tags.map(&value).sort]
  52. grouped_options_for_select(res, current)
  53. end
  54. end

app/helpers/repositories_helper.rb

100.0% lines covered

1 relevant lines. 1 lines covered and 0 lines missed.
    
  1. 1 module RepositoriesHelper
  2. end

app/helpers/statistics_helper.rb

50.0% lines covered

4 relevant lines. 2 lines covered and 2 lines missed.
    
  1. 1 module StatisticsHelper
  2. 1 def statistics_range_options
  3. options_for_select(
  4. StatisticsController::RANGES.map { |r| [I18n.t(r, scope: 'statistics.helper.period'), r] }
  5. )
  6. end
  7. end

app/helpers/title_helper.rb

33.33% lines covered

12 relevant lines. 4 lines covered and 8 lines missed.
    
  1. 1 module TitleHelper
  2. 1 def set_page_title(title)
  3. @current_page_title = title
  4. end
  5. 1 alias_method :title, :set_page_title
  6. 1 def get_page_title(opts = {})
  7. title = (@current_page_title && [@current_page_title]) || []
  8. site_title = opts[:site].presence
  9. title.unshift(site_title) if site_title
  10. title = title.flatten.map(&method(:strip_tags))
  11. title.reverse!
  12. title = safe_join(title, ' - ')
  13. title
  14. end
  15. end

app/helpers/users_helper.rb

33.33% lines covered

12 relevant lines. 4 lines covered and 8 lines missed.
    
  1. 1 module UsersHelper
  2. 1 def avatar_url_by_email(email, size = :small)
  3. avatar_url(User.where(email: email).first || User.new(email: email), size)
  4. end
  5. 1 def avatar_url(subject, size = :small)
  6. if subject.try('avatar?')
  7. subject.avatar.url(size)
  8. elsif subject.kind_of? Group
  9. 'ava-big.png'
  10. else
  11. gravatar_url(subject.email, User::AVATAR_SIZES[size])
  12. end
  13. end
  14. 1 def gravatar_url(email, size = 30)
  15. hex = email.present? ? Digest::MD5.hexdigest(email.try :downcase) : ''
  16. "https://secure.gravatar.com/avatar/#{}?s=#{size}&r=pg"
  17. end
  18. end

app/helpers/wiki_helper.rb

38.18% lines covered

55 relevant lines. 21 lines covered and 34 lines missed.
    
  1. 1 module WikiHelper
  2. 1 def revert_path(project, first, second, name)
  3. if name
  4. revert_page_project_wiki_path(project, CGI.escape(name), first, second)
  5. else
  6. revert_project_wiki_index_path(project, first, second)
  7. end
  8. end
  9. 1 def compare_path(project, name)
  10. if name
  11. compare_project_wiki_path(@project, CGI.escape(name))
  12. else
  13. compare_project_wiki_index_path(@project)
  14. end
  15. end
  16. 1 def escaped_name
  17. CGI.escape(@name)
  18. end
  19. 1 def editor_path(project, name)
  20. if @new
  21. url_for(controller: :wiki, action: :create, project_id: project.id)
  22. else
  23. url_for(controller: :wiki, action: :update, project_id: project.id, id: name)
  24. end
  25. end
  26. 1 def view_path(project, name)
  27. name == 'Home' ? project_wiki_index_path(project) : project_wiki_path(project, name)
  28. end
  29. 1 def wiki_formats
  30. APP_CONFIG['wiki_formats'].map do |key, val|
  31. [ val, key.to_s ]
  32. end.sort do |a, b|
  33. a.first.downcase <=> b.first.downcase
  34. end
  35. end
  36. 1 def footer
  37. if @footer.nil? && @page
  38. @footer = !!@page.footer ? @page.footer : false
  39. end
  40. @footer
  41. end
  42. 1 def sidebar
  43. if @sidebar.nil? && @page
  44. @sidebar = !!@page.sidebar ? @page.sidebar : false
  45. end
  46. @sidebar
  47. end
  48. 1 def has_footer?
  49. @footer = (@page.footer || false) if @footer.nil? && @page
  50. !!@footer
  51. end
  52. 1 def has_sidebar?
  53. @sidebar = (@page.sidebar || false) if @sidebar.nil? && @page
  54. !!@sidebar
  55. end
  56. 1 def footer_content
  57. has_footer? && @footer.formatted_data
  58. end
  59. 1 def footer_format
  60. has_footer? && @footer.format.to_s
  61. end
  62. 1 def sidebar_content
  63. has_sidebar? && @sidebar.formatted_data
  64. end
  65. 1 def sidebar_format
  66. has_sidebar? && @sidebar.format.to_s
  67. end
  68. 1 def author
  69. @page.version.author.name
  70. end
  71. 1 def author_email
  72. @page.version.author.email
  73. end
  74. 1 def user_path_by_user(user)
  75. (user.present?) ? user_path(user) : 'javascript:void(0)'
  76. end
  77. 1 def user_link_by_user(user)
  78. link_to (user.present?) ? user.uname : author, user_path_by_user(user)
  79. end
  80. 1 def date
  81. @page.version.authored_date
  82. end
  83. 1 def format
  84. @page.try(:format) || 'markdown'
  85. end
  86. end

app/jobs/abf_worker/base_observer.rb

55.56% lines covered

27 relevant lines. 15 lines covered and 12 lines missed.
    
  1. 1 module AbfWorker
  2. 1 class BaseObserver
  3. 1 COMPLETED = 0
  4. 1 FAILED = 1
  5. 1 PENDING = 2
  6. 1 STARTED = 3
  7. 1 CANCELED = 4
  8. 1 TESTS_FAILED = 5
  9. 1 attr_accessor :status, :options
  10. 1 def initialize(options, subject_class)
  11. @status = options['status'].to_i
  12. @options = options
  13. @subject_class = subject_class
  14. end
  15. 1 def perform
  16. raise NotImplementedError, "You should implement this method"
  17. end
  18. 1 protected
  19. 1 def subject
  20. @subject ||= @subject_class.find(options['id'])
  21. end
  22. 1 def update_results
  23. now = Time.zone.now.to_i
  24. results = options['results'] || []
  25. results.each{ |r| r['timestamp'] = now }
  26. results += subject.results || []
  27. sort_results_and_save(results)
  28. end
  29. 1 def sort_results_and_save(results, item = subject)
  30. item.results = results.sort_by{ |r| [r['timestamp'].to_s, r['file_name'].to_s] }
  31. item.save(validate: false)
  32. end
  33. end
  34. end

app/jobs/abf_worker/iso_worker_observer.rb

35.71% lines covered

14 relevant lines. 5 lines covered and 9 lines missed.
    
  1. 1 module AbfWorker
  2. 1 class IsoWorkerObserver < AbfWorker::BaseObserver
  3. 1 @queue = :iso_worker_observer
  4. 1 def self.perform(options)
  5. new(options, ProductBuildList).perform
  6. end
  7. 1 def perform
  8. case status
  9. when COMPLETED
  10. subject.build_success
  11. when FAILED
  12. case options['exit_status'].to_i
  13. when ProductBuildList::BUILD_COMPLETED_PARTIALLY
  14. subject.build_success_partially
  15. else
  16. subject.build_error
  17. end
  18. when STARTED
  19. subject.start_build
  20. when CANCELED
  21. subject.build_canceled
  22. end
  23. update_results if status != STARTED
  24. end
  25. end
  26. end

app/jobs/abf_worker/publish_observer.rb

14.55% lines covered

55 relevant lines. 8 lines covered and 47 lines missed.
    
  1. 1 module AbfWorker
  2. 1 class PublishObserver < AbfWorker::BaseObserver
  3. 1 @queue = :publish_observer
  4. 1 def self.perform(options)
  5. new(options, BuildList).perform
  6. end
  7. 1 def perform
  8. return if status == STARTED # do nothing when publication started
  9. extra = options['extra']
  10. repository_status = RepositoryStatus.where(id: extra['repository_status_id']).first
  11. begin
  12. if extra['regenerate'] || extra['regenerate_platform']
  13. log_sha1 = (options['results'].try(:first) || {}).fetch('sha1', nil)
  14. end
  15. if extra['regenerate'] # Regenerate metadata
  16. repository_status.last_regenerated_at = Time.now.utc
  17. repository_status.last_regenerated_status = status
  18. repository_status.last_regenerated_log_sha1 = log_sha1
  19. elsif extra['regenerate_platform'] # Regenerate metadata for Software Center
  20. if platform = Platform.where(id: extra['platform_id']).first
  21. platform.last_regenerated_at = Time.now.utc
  22. platform.last_regenerated_status = status
  23. platform.last_regenerated_log_sha1 = log_sha1
  24. platform.ready
  25. end
  26. elsif extra['create_container'] # Container has been created
  27. case status
  28. when COMPLETED
  29. subject.published_container
  30. when FAILED, CANCELED
  31. subject.fail_publish_container
  32. end
  33. update_results
  34. elsif !extra['resign'] # Simple publish
  35. bls = extra['build_lists_for_cleanup_from_testing']
  36. if status != COMPLETED && bls.present?
  37. AbfWorkerService::Base.cleanup_packages_from_testing(
  38. repository_status.platform_id,
  39. repository_status.repository_id,
  40. bls
  41. )
  42. end
  43. update_rpm_builds
  44. end
  45. ensure
  46. repository_status.ready if repository_status.present?
  47. end
  48. end
  49. 1 protected
  50. 1 def update_rpm_builds
  51. build_lists = BuildList.where(id: options['build_list_ids'])
  52. build_lists.each do |build_list|
  53. update_results build_list
  54. case status
  55. when COMPLETED
  56. if build_list.build_publish?
  57. # 'update_column' - when project of build_list has been removed from repository
  58. build_list.published || build_list.update_column(:status, BuildList::BUILD_PUBLISHED)
  59. elsif build_list.build_publish_into_testing?
  60. build_list.published_into_testing || build_list.update_column(:status, BuildList::BUILD_PUBLISHED_INTO_TESTING)
  61. end
  62. when FAILED, CANCELED
  63. if build_list.build_publish?
  64. build_list.fail_publish || build_list.update_column(:status, BuildList::FAILED_PUBLISH)
  65. elsif build_list.build_publish_into_testing?
  66. build_list.fail_publish_into_testing || build_list.update_column(:status, BuildList::FAILED_PUBLISH_INTO_TESTING)
  67. end
  68. end
  69. AbfWorkerService::Base.unlock_build_list build_list
  70. end
  71. case status
  72. when COMPLETED
  73. AbfWorkerService::Base.cleanup_completed options['projects_for_cleanup']
  74. when FAILED, CANCELED
  75. AbfWorkerService::Base.cleanup_failed options['projects_for_cleanup']
  76. end
  77. end
  78. 1 def update_results(build_list = subject)
  79. results = (build_list.results || []).
  80. select{ |r| r['file_name'] !~ /^abfworker\:\:publish\-(container\-)*worker.*\.log$/ }
  81. results |= options['results']
  82. sort_results_and_save results, build_list
  83. end
  84. end
  85. end

app/jobs/abf_worker/rpm_worker_observer.rb

18.03% lines covered

61 relevant lines. 11 lines covered and 50 lines missed.
    
  1. 1 module AbfWorker
  2. 1 class RpmWorkerObserver < AbfWorker::BaseObserver
  3. 1 RESTARTED_BUILD_LISTS = 'abf-worker::rpm-worker-observer::restarted-build-lists'
  4. # EXIT CODES:
  5. # 6 - Unpermitted architecture
  6. # other - Build error
  7. 1 EXIT_CODE_UNPERMITTED_ARCHITECTURE = 6
  8. 1 @queue = :rpm_worker_observer
  9. 1 def self.perform(options)
  10. new(options, BuildList).perform
  11. end
  12. 1 def perform
  13. return if subject.valid? && restart_task
  14. if options['feedback_from_user']
  15. user = User.find options['feedback_from_user']
  16. return if !user.system? && subject.builder != user
  17. end
  18. item = find_or_create_item
  19. fill_container_data if status != STARTED
  20. unless subject.valid?
  21. Raven.capture_message('Invalid build list', extra: { id: subject.id, errors: subject.errors.map(&:full_message) })
  22. item.update({status: BuildList::BUILD_ERROR})
  23. subject.build_error(false)
  24. subject.save(validate: false)
  25. return
  26. end
  27. if options['hostname']
  28. subject.update_attribute(:hostname, options['hostname'])
  29. end
  30. if options['fail_reason']
  31. subject.update_attribute(:fail_reason, options['fail_reason'])
  32. end
  33. rerunning_tests = subject.rerunning_tests?
  34. case status
  35. when COMPLETED
  36. subject.build_success
  37. if subject.can_auto_publish? && subject.can_publish?
  38. subject.now_publish
  39. elsif subject.auto_publish_into_testing? && subject.can_publish_into_testing?
  40. subject.publish_into_testing
  41. end
  42. when FAILED
  43. case options['exit_status'].to_i
  44. when EXIT_CODE_UNPERMITTED_ARCHITECTURE
  45. subject.unpermitted_arch
  46. else
  47. subject.build_error
  48. end
  49. item.update({status: BuildList::BUILD_ERROR}) unless rerunning_tests
  50. when STARTED
  51. subject.start_build
  52. when CANCELED
  53. item.update({status: BuildList::BUILD_CANCELED}) unless rerunning_tests || subject.tests_failed?
  54. subject.build_canceled
  55. when TESTS_FAILED
  56. subject.tests_failed
  57. end
  58. if !rerunning_tests && [TESTS_FAILED, COMPLETED].include?(status)
  59. item.update({status: BuildList::SUCCESS})
  60. subject.publish_container if subject.auto_create_container?
  61. end
  62. end
  63. 1 protected
  64. 1 def find_or_create_item
  65. subject.items.first || subject.items.create({
  66. version: subject.commit_hash,
  67. name: subject.project.name,
  68. status: BuildList::BUILD_STARTED,
  69. level: 0
  70. })
  71. end
  72. 1 def restart_task
  73. return false if status != FAILED
  74. if Redis.current.lrem(RESTARTED_BUILD_LISTS, 0, subject.id) > 0 || (options['results'] || []).size > 1
  75. return false
  76. else
  77. Redis.current.lpush RESTARTED_BUILD_LISTS, subject.id
  78. subject.update_column(:status, BuildList::BUILD_PENDING)
  79. subject.update_column(:builder_id, nil)
  80. return true
  81. end
  82. end
  83. 1 def fill_container_data
  84. (options['packages'] || []).each do |package|
  85. package = subject.packages.build(package)
  86. package.package_type = package['fullname'] =~ /.*\.src\.rpm$/ ? 'source' : 'binary'
  87. package.project_id = subject.project_id
  88. package.platform_id = subject.save_to_platform_id
  89. package.save!
  90. end
  91. update_results
  92. end
  93. end
  94. end

app/jobs/autostart_builds_daily_job.rb

50.0% lines covered

4 relevant lines. 2 lines covered and 2 lines missed.
    
  1. 1 class AutostartBuildsDailyJob
  2. 1 def self.perform
  3. Product.autostart_iso_builds_once_a_day
  4. Project.autostart_build_lists_once_a_day
  5. end
  6. end

app/jobs/autostart_builds_once_every_twelve_hours_job.rb

50.0% lines covered

4 relevant lines. 2 lines covered and 2 lines missed.
    
  1. 1 class AutostartBuildsOnceEveryTwelveHoursJob
  2. 1 def self.perform
  3. Product.autostart_iso_builds_once_a_12_hours
  4. Project.autostart_build_lists_once_a_12_hours
  5. end
  6. end

app/jobs/autostart_builds_weekly_job.rb

50.0% lines covered

4 relevant lines. 2 lines covered and 2 lines missed.
    
  1. 1 class AutostartBuildsWeeklyJob
  2. 1 def self.perform
  3. Product.autostart_iso_builds_once_a_week
  4. Project.autostart_build_lists_once_a_week
  5. end
  6. end

app/jobs/autostart_regens_daily_job.rb

66.67% lines covered

3 relevant lines. 2 lines covered and 1 lines missed.
    
  1. 1 class AutostartRegensDailyJob
  2. 1 def self.perform
  3. Platform.autostart_metadata_regeneration("day")
  4. end
  5. end

app/jobs/autostart_regens_weekly_job.rb

66.67% lines covered

3 relevant lines. 2 lines covered and 1 lines missed.
    
  1. 1 class AutostartRegensWeeklyJob
  2. 1 def self.perform
  3. Platform.autostart_metadata_regeneration("week")
  4. end
  5. end

app/jobs/build_lists/build_canceling_destroy_job.rb

75.0% lines covered

4 relevant lines. 3 lines covered and 1 lines missed.
    
  1. 1 module BuildLists
  2. 1 class BuildCancelingDestroyJob
  3. 1 def self.perform
  4. BuildList.for_status(BuildList::BUILD_CANCELING).for_notified_date_period(nil, 1.hours.ago).destroy_all
  5. end
  6. end
  7. end

app/jobs/build_lists/clean_buildroot_job.rb

40.0% lines covered

15 relevant lines. 6 lines covered and 9 lines missed.
    
  1. 1 module BuildLists
  2. 1 class CleanBuildrootJob
  3. 1 @queue = :middle
  4. 1 FILENAME = 'buildroot.tar.gz'
  5. 1 def self.perform
  6. build_lists = BuildList.where(save_buildroot: true).
  7. for_status(BuildList::BUILD_ERROR).
  8. where('updated_at < ?', Time.now - 4.days).
  9. where('results ~ ?', "file_name: #{FILENAME}")
  10. build_lists.find_each do |build_list|
  11. buildroots = build_list.results.select do |r|
  12. r['file_name'] == FILENAME
  13. end
  14. build_list.results -= buildroots
  15. build_list.save(validate: false)
  16. clean_file_store buildroots
  17. end
  18. end
  19. 1 def self.clean_file_store(buildroots)
  20. buildroots.each do |r|
  21. FileStoreService::File.new(sha1: r['sha1']).destroy
  22. end
  23. end
  24. end
  25. end

app/jobs/build_lists/create_container_job.rb

57.14% lines covered

7 relevant lines. 4 lines covered and 3 lines missed.
    
  1. 1 module BuildLists
  2. 1 class CreateContainerJob
  3. 1 @queue = :middle
  4. 1 def self.perform(build_list_id)
  5. build_list = BuildList.find(build_list_id)
  6. container = AbfWorkerService::Container.new(build_list)
  7. container.create!
  8. end
  9. end
  10. end

app/jobs/build_lists/dependent_packages_job.rb

12.5% lines covered

32 relevant lines. 4 lines covered and 28 lines missed.
    
  1. 1 module BuildLists
  2. 1 class DependentPackagesJob
  3. 1 @queue = :middle
  4. 1 def self.perform(build_list_id, user_id, project_ids, arch_ids, options)
  5. build_list = BuildList.find(build_list_id)
  6. return if build_list.save_to_platform.personal?
  7. user = User.find(user_id)
  8. return unless BuildListPolicy.new(user, build_list).show?
  9. arches = Arch.where(id: arch_ids).to_a
  10. Project.where(id: project_ids).to_a.each do |project|
  11. next unless ProjectPolicy.new(user, project).write?
  12. build_for_platform = save_to_platform = build_list.build_for_platform
  13. save_to_repository = save_to_platform.repositories.find{ |r| r.projects.exists?(project.id) }
  14. next unless save_to_repository
  15. project_version = project.project_version_for(save_to_platform, build_for_platform)
  16. project.increase_release_tag(project_version, user, "BuildList##{build_list.id}: Increase release tag")
  17. arches.each do |arch|
  18. bl = project.build_lists.build
  19. bl.arch = arch
  20. bl.save_to_repository = save_to_repository
  21. bl.priority = user.build_priority # User builds more priority than mass rebuild with zero priority
  22. bl.project_version = project_version
  23. bl.user = user
  24. bl.include_repos = [build_for_platform.repositories.main.first.try(:id)].compact
  25. bl.include_repos |= [save_to_repository.id]
  26. %i(
  27. build_for_platform_id
  28. update_type
  29. save_to_platform_id
  30. extra_build_lists
  31. extra_params
  32. external_nodes
  33. group_id
  34. ).each { |field| bl[field] = build_list[field] }
  35. bl.auto_publish_status = options['auto_publish_status']
  36. %w(
  37. auto_create_container
  38. include_testing_subrepository
  39. use_cached_chroot
  40. use_extra_tests
  41. ).each { |field| bl[field] = options[field] }
  42. # debug
  43. begin
  44. bl.save! if BuildListPolicy.new(user, bl).create?
  45. rescue ActiveRecord::RecordInvalid => invalid
  46. raise 'DEBUG: ' + invalid.record.errors.map(&:full_message).join('; ')
  47. end
  48. end
  49. end
  50. end
  51. end
  52. end

app/jobs/clean_api_defender_statistics_job.rb

37.5% lines covered

8 relevant lines. 3 lines covered and 5 lines missed.
    
  1. 1 class CleanApiDefenderStatisticsJob
  2. 1 @queue = :low
  3. 1 def self.perform
  4. deadline = Date.today - 1.month
  5. Redis.current.keys.select do |key|
  6. next if key !~ /^throttle:/
  7. # See: https://github.com/datagraph/rack-throttle/blob/master/lib/rack/throttle/daily.rb#L41
  8. # Formats:
  9. # 'throttle:uname:%Y-%m-%dT%H', 'throttle:uname:%Y-%m-%d'
  10. # example: "throttle:uname1:2014-01-25T20", "throttle:uname1:2014-01-25"
  11. date = key.gsub(/.*:/, '').gsub(/T.*/, '')
  12. Redis.current.del(key) if Date.parse(date) < deadline
  13. end
  14. end
  15. end

app/jobs/clean_rpm_build_node_job.rb

60.0% lines covered

5 relevant lines. 3 lines covered and 2 lines missed.
    
  1. 1 class CleanRpmBuildNodeJob
  2. 1 @queue = :middle
  3. 1 def self.perform
  4. RpmBuildNode.all.each do |n|
  5. n.delete unless n.user_id
  6. end
  7. end
  8. end

app/jobs/clean_temp_pull_requests_job.rb

60.0% lines covered

5 relevant lines. 3 lines covered and 2 lines missed.
    
  1. 1 class CleanTempPullRequestsJob
  2. 1 @queue = :low
  3. 1 def self.perform
  4. path = File.join(APP_CONFIG['git_path'], 'temp_pull_requests')
  5. `sh -c "cd #{path} && find -mindepth 3 -maxdepth 3 -type d -mtime +0 | xargs rm -rf && find -maxdepth 2 -type d -empty -delete"`
  6. end
  7. end

app/jobs/clear_stale_builders_job.rb

75.0% lines covered

4 relevant lines. 3 lines covered and 1 lines missed.
    
  1. 1 class ClearStaleBuildersJob
  2. 1 @queue = :low
  3. 1 def self.perform
  4. BuildList.where("updated_at < ?", 300.seconds.ago).
  5. where(status: [BuildList::BUILD_PENDING, BuildList::RERUN_TESTS]).
  6. where.not(builder: nil).update_all('builder_id = NULL')
  7. end
  8. end

app/jobs/clear_unused_invites_job.rb

75.0% lines covered

4 relevant lines. 3 lines covered and 1 lines missed.
    
  1. 1 class ClearUnusedInvitesJob
  2. 1 @queue = :low
  3. 1 def self.perform
  4. Invite.outdated.unused.destroy_all
  5. end
  6. end

app/jobs/create_empty_metadata_job.rb

28.21% lines covered

39 relevant lines. 11 lines covered and 28 lines missed.
    
  1. 1 class CreateEmptyMetadataJob < Struct.new(:class_name, :id)
  2. 1 @queue = :low
  3. 1 def perform
  4. case class_name
  5. when Platform.name
  6. create_empty_metadata_for_platform
  7. when Repository.name
  8. create_empty_metadata_for_repository Repository.find(id)
  9. end
  10. end
  11. 1 def self.perform(class_name, id)
  12. new(class_name, id).perform
  13. end
  14. 1 private
  15. 1 def create_empty_metadata_for_platform
  16. platform = Platform.main.opened.find id
  17. @platforms = [platform]
  18. repositories = Repository.joins(:platform).
  19. where(platforms: { platform_type: Platform::TYPE_PERSONAL })
  20. repositories.find_each do |r|
  21. create_empty_metadata_for_repository r
  22. end
  23. end
  24. 1 def create_empty_metadata_for_repository(repository)
  25. @platforms = [repository.platform] if repository.platform.main?
  26. platforms.each do |platform|
  27. arch_names.each do |arch_name|
  28. %w(release updates).each do |type|
  29. path = "#{ repository.platform.path }/repository/"
  30. path << "#{ platform.name }/" if repository.platform.personal?
  31. path << "#{ arch_name }/#{ repository.name }/#{ type }"
  32. create_empty_metadata(platform, path)
  33. end
  34. end
  35. end
  36. end
  37. 1 def create_empty_metadata(platform, path)
  38. case platform.distrib_type
  39. when 'rhel'
  40. path << '/repodata/'
  41. when 'mdv'
  42. path << '/media_info/'
  43. when 'dnf'
  44. path << '/repodata/'
  45. else
  46. return
  47. end
  48. if Dir["#{ path }/*"].empty?
  49. system "mkdir -p -m 0777 #{ path }"
  50. system "cp -f #{ empty_metadatas(platform) }/* #{ path }/"
  51. end
  52. end
  53. 1 def empty_metadatas(platform)
  54. Rails.root.join('public', 'metadatas', platform.distrib_type).to_s
  55. end
  56. 1 def arch_names
  57. @arch_names ||= Arch.pluck(:name)
  58. end
  59. 1 def platforms
  60. @platforms ||= Platform.main.opened.to_a
  61. end
  62. end

app/jobs/destroy_project_from_repository_job.rb

50.0% lines covered

4 relevant lines. 2 lines covered and 2 lines missed.
    
  1. 1 class DestroyProjectFromRepositoryJob
  2. 1 def self.perform(project, repository)
  3. service = AbfWorkerService::Repository.new(repository)
  4. service.destroy_project!(project)
  5. end
  6. end

app/jobs/publish_task_manager_job.rb

38.1% lines covered

21 relevant lines. 8 lines covered and 13 lines missed.
    
  1. 1 class PublishTaskManagerJob
  2. 1 @queue = :middle
  3. 1 def self.perform
  4. PublishTaskManagerJob.new.perform
  5. end
  6. 1 def perform
  7. regenerate_metadata_for_software_center
  8. resign_repositories
  9. regenerate_metadata
  10. AbfWorkerService::Rpm.publish!
  11. end
  12. 1 protected
  13. 1 def regenerate_metadata_for_software_center
  14. Platform.main.waiting_for_regeneration.each do |platform|
  15. AbfWorkerService::PlatformMetadata.new(platform).regenerate!
  16. end
  17. end
  18. 1 def resign_repositories
  19. statuses = RepositoryStatus.platform_ready.
  20. for_resign.includes(repository: :platform).readonly(false)
  21. statuses.each do |repository_status|
  22. AbfWorkerService::Repository.new(repository_status.repository).resign!(repository_status)
  23. end
  24. end
  25. 1 def regenerate_metadata
  26. statuses = RepositoryStatus.platform_ready.
  27. for_regeneration.includes(repository: :platform).readonly(false)
  28. statuses.each do |repository_status|
  29. AbfWorkerService::RepositoryMetadata.new(repository_status).regenerate!
  30. end
  31. end
  32. end

app/jobs/remove_outdated_items_job.rb

11.76% lines covered

17 relevant lines. 2 lines covered and 15 lines missed.
    
  1. 1 class RemoveOutdatedItemsJob
  2. 1 def self.perform
  3. log_file = Rails.root.join("log", "remove_outdated.log").to_s
  4. counter_bl = 0
  5. BuildList.outdated.find_each(batch_size: 100) do |bl|
  6. bl.destroy && (counter_bl += 1) if bl.id != bl.last_published.first.try(:id)
  7. end
  8. counter_mb = 0
  9. MassBuild.outdated.find_each do |mb|
  10. mb.destroy && (counter_mb += 1) if mb.build_lists.count == 0
  11. end
  12. User.find_each do |user|
  13. user.activity_feeds.outdated.destroy_all
  14. end
  15. counter_pbl = ProductBuildList.outdated.count
  16. ProductBuildList.outdated.destroy_all
  17. File.open(log_file, "w") do |f|
  18. f.puts "Build Lists deleted: #{counter_bl}"
  19. f.puts "Mass Builds deleted: #{counter_mb}"
  20. f.puts "Product Build Lists deleted: #{counter_pbl}"
  21. end
  22. end
  23. end

app/jobs/restart_nodes_job.rb

50.0% lines covered

6 relevant lines. 3 lines covered and 3 lines missed.
    
  1. 1 class RestartNodesJob
  2. 1 @queue = :low
  3. 1 def self.perform
  4. return if NodeInstruction.all_locked?
  5. available_nodes = RpmBuildNode.all.map{ |n| n.user_id if n.user.try(:system?) }.compact.uniq
  6. NodeInstruction.where(status: NodeInstruction::READY).
  7. where.not(user_id: available_nodes).find_each(&:restart)
  8. end
  9. end

app/jobs/run_extra_mass_builds_job.rb

42.86% lines covered

14 relevant lines. 6 lines covered and 8 lines missed.
    
  1. 1 class RunExtraMassBuildsJob
  2. 1 @queue = :low
  3. 1 def self.perform
  4. RunExtraMassBuildsJob.new.perform
  5. end
  6. 1 def perform
  7. MassBuild.where(status: MassBuild::BUILD_PENDING).find_each do |mb|
  8. next if mb.extra_mass_builds.blank?
  9. emb = MassBuild.where(status: MassBuild::SUCCESS, id: mb.extra_mass_builds).to_a
  10. next if emb.size != mb.extra_mass_builds.size
  11. next if emb.find{ |mb| not_ready?(mb) }
  12. mb.build_all
  13. end
  14. end
  15. 1 private
  16. # Returns true if mass build has not published packages or packages without container
  17. 1 def not_ready?(mb)
  18. mb.build_lists.count != mb.build_lists.where(
  19. 'status = ? OR container_status = ?',
  20. BuildList::BUILD_PUBLISHED,
  21. BuildList::BUILD_PUBLISHED
  22. ).count
  23. end
  24. end

app/mailers/user_mailer.rb

32.73% lines covered

55 relevant lines. 18 lines covered and 37 lines missed.
    
  1. 1 class UserMailer < ActionMailer::Base
  2. 1 helper ActivityFeedsHelper
  3. 1 helper CommitHelper
  4. 1 default from: "\"#{APP_CONFIG['project_name']}\" <#{APP_CONFIG['do-not-reply-email']}>"
  5. 1 default_url_options.merge!(protocol: 'https') if APP_CONFIG['mailer_https_url']
  6. 1 include Resque::Mailer # send email async
  7. 1 def new_user_notification(user)
  8. @user = user
  9. mail(
  10. to: email_with_name(user, user.email),
  11. subject: I18n.t("notifications.subjects.new_user_notification",
  12. project_name: APP_CONFIG['project_name'])
  13. ) do |format|
  14. format.html
  15. end
  16. end
  17. 1 def new_comment_notification(comment, user_id)
  18. @user, @comment = User.find(user_id), comment
  19. subject = @comment.issue_comment? ? subject_for_issue(@comment.commentable) :
  20. I18n.t('notifications.subjects.new_commit_comment_notification')
  21. mail(
  22. to: email_with_name(@user, @user.email),
  23. subject: subject,
  24. from: email_with_name(comment.user)
  25. ) do |format|
  26. format.html
  27. end
  28. end
  29. 1 def new_issue_notification(issue_id, user_id)
  30. @user, @issue = User.find(user_id), Issue.find(issue_id)
  31. mail(
  32. to: email_with_name(@user, @user.email),
  33. subject: subject_for_issue(@issue, true),
  34. from: email_with_name(@issue.user)
  35. ) do |format|
  36. format.html
  37. end
  38. end
  39. 1 def issue_assign_notification(issue, user)
  40. @issue = issue
  41. mail(
  42. to: email_with_name(user, user.email),
  43. subject: subject_for_issue(@issue)
  44. ) do |format|
  45. format.html
  46. end
  47. end
  48. 1 def build_list_notification(build_list, user)
  49. set_locale user
  50. @user, @build_list = user, build_list
  51. subject = "[№ #{build_list.id}] "
  52. subject << (build_list.project ? build_list.project.name_with_owner : t("layout.projects.unexisted_project"))
  53. subject << " - #{build_list.human_status} "
  54. subject << I18n.t("notifications.subjects.for_arch", arch: @build_list.arch.name)
  55. mail(
  56. to: email_with_name(user, user.email),
  57. subject: subject,
  58. from: email_with_name(build_list.publisher || build_list.user)
  59. ) do |format|
  60. format.html
  61. end
  62. end
  63. 1 def metadata_regeneration_notification(platform, user)
  64. set_locale user
  65. @user, @platform = user, platform
  66. subject = "[#{platform.name}] "
  67. subject << I18n.t("notifications.subjects.metadata_regeneration", status: I18n.t("layout.regeneration_statuses.last_regenerated_statuses.#{platform.human_regeneration_status}"))
  68. mail(
  69. to: email_with_name(user, user.email),
  70. subject: subject,
  71. from: email_with_name(platform.owner)
  72. ) do |format|
  73. format.html
  74. end
  75. end
  76. 1 def git_delete_branch_notification(user, options)
  77. set_locale user
  78. mail(
  79. to: user.email,
  80. subject: I18n.t('notifications.subjects.update_code', project_name: "#{options[:project_owner]}/#{options[:project_name]}")
  81. ) do |format|
  82. format.html { render 'git_delete_branch_notification', locals: options }
  83. end
  84. end
  85. 1 def git_new_push_notification(user, options)
  86. set_locale user
  87. mail(
  88. to: user.email,
  89. subject: I18n.t('notifications.subjects.update_code', project_name: "#{options[:project_owner]}/#{options[:project_name]}")
  90. ) do |format|
  91. format.html { render 'git_new_push_notification', locals: options }
  92. end
  93. end
  94. 1 protected
  95. 1 def set_locale(user)
  96. I18n.locale = user.language if user.language
  97. end
  98. 1 def email_with_name(user, email = APP_CONFIG['do-not-reply-email'])
  99. "\"#{user.user_appeal}\" <#{email}>"
  100. end
  101. 1 def subject_for_issue(issue, new_issue = false)
  102. subject = new_issue ? '' : 'Re: '
  103. subject << "[#{issue.project.name}] #{issue.title} (##{issue.serial_id})"
  104. end
  105. end

app/models/activity_feed.rb

93.33% lines covered

15 relevant lines. 14 lines covered and 1 lines missed.
    
  1. 1 class ActivityFeed < ActiveRecord::Base
  2. 1 CODE = %w(git_delete_branch_notification git_new_push_notification new_comment_commit_notification)
  3. 1 TRACKER = %w(issue_assign_notification new_comment_notification new_issue_notification)
  4. 1 BUILD = %w(build_list_notification)
  5. 1 WIKI = %w(wiki_new_commit_notification)
  6. 1 belongs_to :user
  7. 1 belongs_to :creator, class_name: 'User', optional: true
  8. 1 serialize :data
  9. 61 default_scope { order created_at: :desc }
  10. 1 scope :outdated, -> { offset(1000) }
  11. 1 scope :by_project_name, ->(name) { where(project_name: name) if name.present? }
  12. 1 scope :by_owner_uname, ->(owner) { where(project_owner: owner) if owner.present? }
  13. 1 self.per_page = 20
  14. 1 def partial
  15. "home/partials/#{self.kind}"
  16. end
  17. end

app/models/advisory.rb

47.92% lines covered

48 relevant lines. 23 lines covered and 25 lines missed.
    
  1. 1 class Advisory < ActiveRecord::Base
  2. 1 self.include_root_in_json = false
  3. 1 self.per_page = 30
  4. 1 has_and_belongs_to_many :platforms
  5. 1 has_and_belongs_to_many :projects
  6. 1 has_many :build_lists
  7. 1 validates :description, :update_type, presence: true
  8. 1 validates :update_type, inclusion: BuildList::RELEASE_UPDATE_TYPES
  9. 1 after_create :generate_advisory_id
  10. 1 before_save :normalize_references, if: :references_changed?
  11. 1 ID_TEMPLATE = 'ROSA-%<type>s-%<year>d:%<id>04d'
  12. 1 ID_STRING_TEMPLATE = 'ROSA-%<type>s-%<year>04s:%<id>04s'
  13. 1 TYPES = {'security' => 'SA', 'bugfix' => 'A'}
  14. 1 scope :search_like, ->(q) {
  15. q = q.to_s.strip
  16. where("#{table_name}.advisory_id ILIKE :q OR #{table_name}.description ILIKE :q OR build_list_packages.fullname ILIKE :q", q: "%#{q}%").
  17. joins(build_lists: :packages) if q.present?
  18. }
  19. 1 scope :search_by_id, ->(aid) { where("#{table_name}.advisory_id ILIKE ?", "%#{aid.to_s.strip}%") }
  20. 1 scope :by_update_type, ->(ut) { where(update_type: ut) }
  21. 1 default_scope { order(created_at: :desc) }
  22. 1 def to_param
  23. advisory_id
  24. end
  25. 1 def attach_build_list(build_list)
  26. return false if update_type != build_list.update_type
  27. self.platforms << build_list.save_to_platform unless platforms.include? build_list.save_to_platform
  28. self.projects << build_list.project unless projects.include? build_list.project
  29. build_list.advisory = self
  30. save && build_list.save
  31. end
  32. # this method fetches and structurize packages attached to current advisory.
  33. 1 def fetch_packages_info
  34. packages_info = Hash.new { |h, k| h[k] = {} } # maaagic, it's maaagic ;)
  35. build_lists.includes(:save_to_platform, :packages, :project).find_in_batches do |batch|
  36. batch.each do |build_list|
  37. tmp = build_list.packages.inject({srpm: nil, rpm: []}) do |h, p|
  38. p.package_type == 'binary' ? h[:rpm] << p.fullname : h[:srpm] = p.fullname
  39. h
  40. end
  41. h = { build_list.project => tmp }
  42. packages_info[build_list.save_to_platform].merge!(h) do |pr, old, new|
  43. {srpm: new[:srpm], rpm: old[:rpm].concat(new[:rpm]).uniq}
  44. end
  45. end
  46. end
  47. packages_info
  48. end
  49. 1 protected
  50. 1 def generate_advisory_id
  51. self.advisory_id = sprintf(ID_TEMPLATE, type: TYPES[self.update_type], year: Time.now.utc.year, id: self.id)
  52. self.save
  53. end
  54. 1 def normalize_references
  55. self.references.gsub!(/\r| /, '')
  56. self.references = self.references.split('\n').map do |ref|
  57. ref = CGI::escapeHTML(ref)
  58. ref = "http://#{ref}" unless ref =~ %r[^http(s?)://*]
  59. ref
  60. end.join("\n")
  61. end
  62. end

app/models/arch.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. 1 class Arch < ActiveRecord::Base
  2. 1 DEFAULT = %w[i586 x86_64]
  3. 1 has_many :build_lists, dependent: :destroy
  4. 1 validates :name, presence: true, uniqueness: true
  5. 1 scope :recent, -> { order(:name) }
  6. end

app/models/avatar.rb

100.0% lines covered

11 relevant lines. 11 lines covered and 0 lines missed.
    
  1. 1 class Avatar < ActiveRecord::Base
  2. 1 self.abstract_class = true
  3. 1 MAX_AVATAR_SIZE = 5.megabyte
  4. 1 AVATAR_SIZES = { micro: 16, small: 30, medium: 40, big: 81 }
  5. 1 AVATAR_SIZES_HASH = {}.tap do |styles|
  6. 1 AVATAR_SIZES.each do |name, size|
  7. 4 styles[name] = { geometry: "#{size}x#{size}#", format: :jpg,
  8. convert_options: '-strip -background white -flatten -quality 70' }
  9. end
  10. end
  11. 1 has_attached_file :avatar, styles: AVATAR_SIZES_HASH
  12. 1 validates_attachment_size :avatar, less_than_or_equal_to: MAX_AVATAR_SIZE
  13. 1 validates_attachment_content_type :avatar, content_type: /\Aimage/
  14. 1 validates_attachment_file_name :avatar, matches: [ /(png|jpe?g|gif|bmp|tif?f)\z/i ]
  15. end

app/models/build_list.rb

59.32% lines covered

354 relevant lines. 210 lines covered and 144 lines missed.
    
  1. 1 class BuildList < ActiveRecord::Base
  2. 1 include CommitAndVersion
  3. 1 include FileStoreClean
  4. 1 include AbfWorkerMethods
  5. 1 include Feed::BuildList
  6. 1 include BuildListObserver
  7. 1 include EventLoggable
  8. 1 include ExternalNodable
  9. 1 self.per_page = 25
  10. 1 belongs_to :project
  11. 1 belongs_to :arch
  12. 1 belongs_to :save_to_platform, class_name: 'Platform'
  13. 1 belongs_to :save_to_repository, class_name: 'Repository'
  14. 1 belongs_to :build_for_platform, class_name: 'Platform'
  15. 1 belongs_to :user
  16. 1 belongs_to :builder, class_name: 'User', optional: true
  17. 1 belongs_to :publisher, class_name: 'User', optional: true
  18. 1 belongs_to :advisory, optional: true
  19. 1 belongs_to :mass_build, counter_cache: true, optional: true
  20. 1 has_many :items, class_name: '::BuildList::Item', dependent: :destroy
  21. 1 has_many :packages, class_name: '::BuildList::Package', dependent: :destroy
  22. 1 has_many :source_packages, -> { where(package_type: 'source') }, class_name: '::BuildList::Package'
  23. UPDATE_TYPES = [
  24. 1 UPDATE_TYPE_BUGFIX = 'bugfix',
  25. UPDATE_TYPE_SECURITY = 'security',
  26. UPDATE_TYPE_ENHANCEMENT = 'enhancement',
  27. UPDATE_TYPE_RECOMMENDED = 'recommended',
  28. UPDATE_TYPE_NEWPACKAGE = 'newpackage'
  29. ]
  30. 1 RELEASE_UPDATE_TYPES = [UPDATE_TYPE_BUGFIX, UPDATE_TYPE_SECURITY]
  31. 1 EXTRA_PARAMS = %w[cfg_options cfg_urpm_options build_src_rpm build_rpm]
  32. AUTO_PUBLISH_STATUSES = [
  33. 1 AUTO_PUBLISH_STATUS_NONE = 'none',
  34. AUTO_PUBLISH_STATUS_DEFAULT = 'default',
  35. AUTO_PUBLISH_STATUS_TESTING = 'testing'
  36. ]
  37. 1 validates :project, :project_id,
  38. :project_version,
  39. :arch, :arch_id,
  40. :include_repos,
  41. :build_for_platform, :build_for_platform_id,
  42. :save_to_platform, :save_to_platform_id,
  43. :save_to_repository, :save_to_repository_id,
  44. presence: true
  45. 1 validates_numericality_of :priority, greater_than_or_equal_to: 0
  46. 1 validates :auto_publish_status, inclusion: { in: AUTO_PUBLISH_STATUSES }
  47. 1 validates :update_type, inclusion: UPDATE_TYPES,
  48. 6 unless: Proc.new { |b| b.advisory.present? }
  49. 1 validates :update_type, inclusion: { in: RELEASE_UPDATE_TYPES, message: I18n.t('flash.build_list.frozen_platform') },
  50. 6 if: Proc.new { |b| b.advisory.present? }
  51. 1 validate -> {
  52. 6 if save_to_platform.try(:main?) && save_to_platform_id != build_for_platform_id
  53. errors.add(:build_for_platform, I18n.t('flash.build_list.wrong_platform'))
  54. end
  55. }
  56. 1 validate -> {
  57. 6 unless build_for_platform.try :main?
  58. errors.add(:build_for_platform, I18n.t('flash.build_list.wrong_build_for_platform'))
  59. end
  60. }
  61. 1 validate -> {
  62. 6 if save_to_repository.try(:platform_id) != save_to_platform.try(:id)
  63. errors.add(:save_to_repository, I18n.t('flash.build_list.wrong_repository'))
  64. end
  65. }
  66. 1 validate -> {
  67. 6 if build_for_platform && build_for_platform.repositories.where(id: include_repos).count != include_repos.try(:size)
  68. errors.add(:save_to_repository, I18n.t('flash.build_list.wrong_include_repos'))
  69. end
  70. }
  71. 1 validate -> {
  72. 6 unless save_to_repository && save_to_repository.projects.exists?(project_id)
  73. errors.add(:save_to_repository, I18n.t('flash.build_list.wrong_project'))
  74. end
  75. }
  76. 1 before_validation -> {
  77. 3 self.include_repos = ([] << include_repos).flatten.uniq if include_repos.present?
  78. }, on: :create
  79. 1 before_validation :prepare_extra_repositories, on: :create
  80. 1 before_validation :prepare_extra_build_lists, on: :create
  81. 1 before_validation :prepare_extra_params, on: :create
  82. 1 before_validation :prepare_auto_publish_status, on: :create
  83. 1 LIVE_TIME = 4.week # for unpublished
  84. 1 MAX_LIVE_TIME = 3.month # for published
  85. 1 STATUSES, HUMAN_STATUSES = [], {}
  86. [
  87. 1 %w(SUCCESS 0),
  88. # %w(ERROR 1),
  89. # %w(PROJECT_SOURCE_ERROR 6),
  90. # %w(DEPENDENCIES_ERROR 555),
  91. %w(BUILD_ERROR 666),
  92. %w(PACKAGES_FAIL 777),
  93. %w(BUILD_STARTED 3000),
  94. %w(BUILD_CANCELED 5000),
  95. %w(WAITING_FOR_RESPONSE 4000),
  96. %w(BUILD_PENDING 2000),
  97. %w(RERUN_TESTS 2500),
  98. %w(RERUNNING_TESTS 2550),
  99. %w(BUILD_PUBLISHED 6000),
  100. %w(BUILD_PUBLISH 7000),
  101. %w(FAILED_PUBLISH 8000),
  102. %w(REJECTED_PUBLISH 9000),
  103. %w(BUILD_CANCELING 10000),
  104. %w(TESTS_FAILED 11000),
  105. %w(BUILD_PUBLISHED_INTO_TESTING 12000),
  106. %w(BUILD_PUBLISH_INTO_TESTING 13000),
  107. %w(FAILED_PUBLISH_INTO_TESTING 14000),
  108. %w(UNPERMITTED_ARCH 15000)
  109. ].each do |kind, value|
  110. 19 value = value.to_i
  111. 19 const_set kind, value
  112. 19 STATUSES << value
  113. 19 HUMAN_STATUSES[value] = kind.downcase.to_sym
  114. end
  115. 1 STATUSES.freeze
  116. 1 HUMAN_STATUSES.freeze
  117. 4 scope :recent, -> { order(updated_at: :desc) }
  118. 1 scope :for_extra_build_lists, ->(ids, save_to_platform) {
  119. s = where(id: ids, container_status: BuildList::BUILD_PUBLISHED)
  120. s = s.where(save_to_platform_id: save_to_platform.id) if save_to_platform && save_to_platform.main?
  121. s
  122. }
  123. 4 scope :for_status, ->(status) { where(status: status) if status.present? }
  124. 1 scope :for_user, ->(user) { where(user_id: user.id) }
  125. 1 scope :not_owned_external_nodes, -> { where("#{table_name}.external_nodes is null OR #{table_name}.external_nodes != ?", :owned) }
  126. 1 scope :external_nodes, ->(type) { where("#{table_name}.external_nodes = ?", type) }
  127. 1 scope :oldest, -> { where("#{table_name}.updated_at < ?", Time.zone.now - 15.seconds) }
  128. 4 scope :for_platform, ->(platform) { where(build_for_platform_id: platform) if platform.present? }
  129. 1 scope :by_mass_build, ->(mass_build) { where(mass_build_id: mass_build) }
  130. 4 scope :scoped_to_arch, ->(arch) { where(arch_id: arch) if arch.present? }
  131. 1 scope :scoped_to_save_platform, ->(pl_id) { where(save_to_platform_id: pl_id) if pl_id.present? }
  132. 1 scope :scoped_to_build_for_platform, ->(pl_id) { where(build_for_platform_id: pl_id) if pl_id.present? }
  133. 1 scope :scoped_to_save_to_repository, ->(repo_id) { where(save_to_repository_id: repo_id) if repo_id.present? }
  134. 1 scope :scoped_to_project_version, ->(pr_version) { where(project_version: pr_version) if pr_version.present? }
  135. 1 scope :scoped_to_is_circle, ->(is_circle) { where(is_circle: is_circle) }
  136. 1 scope :for_creation_date_period, ->(start_date, end_date) {
  137. s = all
  138. s = s.where(["#{table_name}.created_at >= ?", start_date]) if start_date
  139. s = s.where(["#{table_name}.created_at <= ?", end_date]) if end_date
  140. s
  141. }
  142. 1 scope :for_notified_date_period, ->(start_date, end_date) {
  143. s = all
  144. s = s.where("#{table_name}.updated_at >= ?", start_date) if start_date.present?
  145. s = s.where("#{table_name}.updated_at <= ?", end_date) if end_date.present?
  146. s
  147. }
  148. 1 scope :scoped_to_project_name, ->(project_name) {
  149. joins(:project).where('projects.name LIKE ?', "%#{project_name}%") if project_name.present?
  150. }
  151. 1 scope :scoped_to_new_core, ->(new_core) { where(new_core: new_core) }
  152. 1 scope :outdated, -> (now = Time.now) {
  153. where(<<-SQL, now - LIVE_TIME, [BUILD_PUBLISHED,BUILD_PUBLISHED_INTO_TESTING], now - MAX_LIVE_TIME)
  154. (
  155. #{table_name}.created_at < ? AND
  156. #{table_name}.status NOT IN (?) AND
  157. #{table_name}.mass_build_id IS NULL
  158. ) OR (
  159. #{table_name}.created_at < ?
  160. )
  161. SQL
  162. }
  163. 1 scope :published_container, -> { where(container_status: BUILD_PUBLISHED) }
  164. 1 serialize :additional_repos
  165. 1 serialize :include_repos
  166. 1 serialize :results, Array
  167. 1 serialize :extra_repositories, Array
  168. 1 serialize :extra_build_lists, Array
  169. 1 serialize :extra_params, Hash
  170. 1 after_create :place_build
  171. 1 after_destroy :remove_container
  172. 1 state_machine :status, initial: :waiting_for_response do
  173. 1 after_transition on: :published,
  174. do: %i(set_version_and_tag actualize_packages)
  175. 1 after_transition on: :publish, do: :set_publisher
  176. 1 after_transition(on: :publish) do |build_list, transition|
  177. if transition.from == BUILD_PUBLISHED_INTO_TESTING
  178. build_list.cleanup_packages_from_testing
  179. end
  180. end
  181. 1 after_transition on: :cancel, do: :cancel_job
  182. 1 after_transition on: %i(published fail_publish build_error tests_failed unpermitted_arch), do: :notify_users
  183. 1 after_transition on: :build_success, do: :notify_users,
  184. unless: ->(build_list) { build_list.auto_publish? || build_list.auto_publish_into_testing? }
  185. 1 event :place_build do
  186. 1 transition waiting_for_response: :build_pending
  187. end
  188. 1 event :unpermitted_arch do
  189. 1 transition [:build_started, :build_canceling, :build_canceled] => :unpermitted_arch
  190. end
  191. 1 event :rerun_tests do
  192. 1 transition %i(success tests_failed) => :rerun_tests
  193. end
  194. 1 event :start_build do
  195. 1 transition build_pending: :build_started
  196. 1 transition rerun_tests: :rerunning_tests
  197. end
  198. 1 event :cancel do
  199. 1 transition [:build_pending, :build_started] => :build_canceling
  200. 1 transition [:rerun_tests, :rerunning_tests] => :tests_failed
  201. end
  202. # build_canceling: :build_canceled - canceling from UI
  203. # build_started: :build_canceled - canceling from worker by time-out (time_living has been expired)
  204. 1 event :build_canceled do
  205. 1 transition [:build_canceling, :build_started, :build_pending] => :build_canceled
  206. 1 transition [:rerun_tests, :rerunning_tests] => :tests_failed
  207. end
  208. 1 event :published do
  209. 1 transition [:build_publish, :rejected_publish] => :build_published
  210. end
  211. 1 event :fail_publish do
  212. 1 transition [:build_publish, :rejected_publish] => :failed_publish
  213. end
  214. 1 event :publish do
  215. 1 transition [
  216. :success,
  217. :failed_publish,
  218. :build_published,
  219. :tests_failed,
  220. :failed_publish_into_testing,
  221. :build_published_into_testing
  222. ] => :build_publish
  223. 1 transition [:success, :failed_publish, :failed_publish_into_testing] => :failed_publish
  224. end
  225. 1 event :reject_publish do
  226. 1 transition [
  227. :success,
  228. :failed_publish,
  229. :tests_failed,
  230. :failed_publish_into_testing,
  231. :build_published_into_testing
  232. ] => :rejected_publish
  233. end
  234. # ===== into testing - start
  235. 1 event :published_into_testing do
  236. 1 transition [:build_publish_into_testing, :rejected_publish] => :build_published_into_testing
  237. end
  238. 1 event :fail_publish_into_testing do
  239. 1 transition [:build_publish_into_testing, :rejected_publish] => :failed_publish_into_testing
  240. end
  241. 1 event :publish_into_testing do
  242. 1 transition [
  243. :success,
  244. :failed_publish,
  245. :tests_failed,
  246. :failed_publish_into_testing,
  247. :build_published_into_testing
  248. ] => :build_publish_into_testing
  249. 1 transition [:success, :failed_publish, :failed_publish_into_testing] => :failed_publish_into_testing
  250. end
  251. # ===== into testing - end
  252. 1 event :build_success do
  253. 1 transition [:build_started, :build_canceling, :build_canceled, :rerunning_tests, :build_pending] => :success
  254. end
  255. 1 [:build_error, :tests_failed].each do |kind|
  256. 2 event kind do
  257. 2 transition [:build_started, :build_canceling, :build_canceled, :build_pending] => kind
  258. 2 transition rerunning_tests: :tests_failed
  259. end
  260. end
  261. 1 HUMAN_STATUSES.each do |code,name|
  262. 19 state name, value: code
  263. end
  264. end
  265. 1 later :publish, queue: :middle
  266. 1 HUMAN_CONTAINER_STATUSES = { WAITING_FOR_RESPONSE => :waiting_for_publish,
  267. BUILD_PUBLISHED => :container_published,
  268. BUILD_PUBLISH => :container_publish,
  269. FAILED_PUBLISH => :container_failed_publish
  270. }.freeze
  271. 1 state_machine :container_status, initial: :waiting_for_publish do
  272. 1 after_transition on: :publish_container, do: :create_container
  273. 1 after_transition on: [:fail_publish_container, :destroy_container],
  274. do: :remove_container
  275. 1 event :publish_container do
  276. 1 transition [:waiting_for_publish, :container_failed_publish] => :container_publish,
  277. if: :can_create_container?
  278. end
  279. 1 event :published_container do
  280. 1 transition container_publish: :container_published
  281. end
  282. 1 event :fail_publish_container do
  283. 1 transition container_publish: :container_failed_publish
  284. end
  285. 1 event :destroy_container do
  286. 1 transition [:container_failed_publish, :container_published, :waiting_for_publish] => :waiting_for_publish
  287. end
  288. 1 HUMAN_CONTAINER_STATUSES.each do |code,name|
  289. 4 state name, value: code
  290. end
  291. end
  292. 1 def set_version_and_tag
  293. pkg = self.packages.where(package_type: 'source', project_id: self.project_id).first
  294. # TODO: remove 'return' after deployment ABF kernel 2.0
  295. return if pkg.nil? # For old client that does not sends data about packages
  296. self.package_version = "#{pkg.platform.name}-#{pkg.version}-#{pkg.release}"
  297. system("cd #{self.project.repo.path} && git tag #{self.package_version} #{self.commit_hash}") # TODO REDO through grit
  298. save
  299. end
  300. 1 def actualize_packages
  301. ActiveRecord::Base.transaction do
  302. # packages from previous build_list
  303. self.last_published.limit(2).last.packages.update_all actual: false
  304. self.packages.update_all actual: true
  305. end
  306. end
  307. 1 def can_create_container?
  308. [SUCCESS, BUILD_PUBLISH, FAILED_PUBLISH, BUILD_PUBLISHED, TESTS_FAILED, BUILD_PUBLISHED_INTO_TESTING, FAILED_PUBLISH_INTO_TESTING].include?(status) && [WAITING_FOR_RESPONSE, FAILED_PUBLISH].include?(container_status)
  309. end
  310. 1 def can_publish_into_repository?
  311. return true if !save_to_repository.synchronizing_publications? || save_to_platform.personal? || project.architecture_dependent?
  312. arch_ids = save_to_platform.platform_arch_settings.by_default.pluck(:arch_id)
  313. BuildList.where(
  314. project_id: project_id,
  315. save_to_repository_id: save_to_repository_id,
  316. arch_id: arch_ids,
  317. commit_hash: commit_hash,
  318. status: [
  319. SUCCESS,
  320. BUILD_PUBLISHED,
  321. BUILD_PUBLISH,
  322. FAILED_PUBLISH,
  323. TESTS_FAILED,
  324. BUILD_PUBLISHED_INTO_TESTING,
  325. BUILD_PUBLISH_INTO_TESTING,
  326. FAILED_PUBLISH_INTO_TESTING
  327. ]
  328. ).group(:arch_id).count == arch_ids.size
  329. end
  330. #TODO: Share this checking on product owner.
  331. 1 def can_cancel?
  332. build_started? || build_pending?
  333. end
  334. # Comparison between versions of current and last published build_list
  335. # @return [Boolean]
  336. # - false if no new packages
  337. # - false if version of packages is less than version of pubished packages.
  338. # - true if version of packages is equal to version of pubished packages (only if platform is not released or platform is RHEL).
  339. # - true if version of packages is greater than version of pubished packages.
  340. 1 def has_new_packages?
  341. if last_bl = last_published.joins(:source_packages).where(build_list_packages: {actual: true}).last
  342. source_packages.each do |nsp|
  343. sp = last_bl.source_packages.find{ |sp| nsp.name == sp.name }
  344. return true unless sp
  345. comparison = nsp.rpmvercmp(sp)
  346. return true if comparison == 1
  347. return comparison == 0 && ( !save_to_platform.released? || save_to_platform.distrib_type == 'rhel' )
  348. end
  349. else
  350. return true # no published packages
  351. end
  352. return false # no new packages
  353. end
  354. 1 def auto_publish?
  355. 6 auto_publish_status == AUTO_PUBLISH_STATUS_DEFAULT
  356. end
  357. 1 def auto_publish_into_testing?
  358. auto_publish_status == AUTO_PUBLISH_STATUS_TESTING
  359. end
  360. # TODO: remove later
  361. 1 def auto_publish=(value)
  362. self.auto_publish_status = value.present? ? AUTO_PUBLISH_STATUS_DEFAULT : AUTO_PUBLISH_STATUS_NONE
  363. end
  364. 1 def can_auto_publish?
  365. auto_publish? && can_publish? && has_new_packages? && can_publish_into_repository?
  366. end
  367. 1 def can_publish?
  368. super &&
  369. valid_branch_for_publish? &&
  370. extra_build_lists_published? &&
  371. save_to_repository.projects.exists?(id: project_id)
  372. end
  373. 1 def can_publish_into_testing?
  374. super && valid_branch_for_publish?
  375. end
  376. 1 def extra_build_lists_published?
  377. # All extra build lists should be published before publishing this build list for main platforms!
  378. return true unless save_to_platform.main?
  379. BuildList.where(id: extra_build_lists).where('status != ?', BUILD_PUBLISHED).count == 0
  380. end
  381. 1 def human_average_build_time
  382. I18n.t('layout.project_statistics.human_average_build_time', {hours: (average_build_time/3600).to_i, minutes: (average_build_time%3600/60).to_i})
  383. end
  384. 1 def formatted_average_build_time
  385. "%02d:%02d" % [average_build_time / 3600, average_build_time % 3600 / 60]
  386. end
  387. 1 def average_build_time
  388. return 0 unless project
  389. @average_build_time ||= project.project_statistics.
  390. find{ |ps| ps.arch_id == arch_id }.try(:average_build_time) || 0
  391. end
  392. 1 def self.human_status(status)
  393. I18n.t("layout.build_lists.statuses.#{HUMAN_STATUSES[status]}")
  394. end
  395. 1 def human_status
  396. self.class.human_status(status)
  397. end
  398. 1 def self.status_by_human(human)
  399. HUMAN_STATUSES.key human
  400. end
  401. 1 def set_items(items_hash)
  402. self.items = []
  403. items_hash.each do |level, items|
  404. items.each do |item|
  405. self.items << self.items.build(name: item['name'], version: item['version'], level: level.to_i)
  406. end
  407. end
  408. end
  409. 1 def set_packages(pkg_hash, project_name)
  410. prj = Project.joins(repositories: :platform).where('platforms.id = ?', save_to_platform.id).find_by!(name: project_name)
  411. build_package(pkg_hash['srpm'], 'source', prj) {|p| p.save!}
  412. pkg_hash['rpm'].each do |rpm_hash|
  413. build_package(rpm_hash, 'binary', prj) {|p| p.save!}
  414. end
  415. end
  416. 1 def event_log_message
  417. {project: project.name, version: project_version, arch: arch.name}.inspect
  418. end
  419. 1 def current_duration
  420. if started_at
  421. (Time.now.utc - started_at.utc).to_i
  422. else
  423. 0
  424. end
  425. end
  426. 1 def human_current_duration
  427. I18n.t("layout.build_lists.human_current_duration", {hours: (current_duration/3600).to_i, minutes: (current_duration%3600/60).to_i})
  428. end
  429. 1 def human_duration
  430. I18n.t("layout.build_lists.human_duration", {hours: (duration.to_i/3600).to_i, minutes: (duration.to_i%3600/60).to_i})
  431. end
  432. 1 def in_work?
  433. status == BUILD_STARTED
  434. #[WAITING_FOR_RESPONSE, BUILD_PENDING, BUILD_STARTED].include?(status)
  435. end
  436. 1 def associate_and_create_advisory(params)
  437. build_advisory(params){ |a| a.update_type = update_type }
  438. advisory.attach_build_list(self)
  439. end
  440. 1 def can_attach_to_advisory?
  441. !save_to_repository.publish_without_qa &&
  442. save_to_platform.main? &&
  443. save_to_platform.released &&
  444. build_published?
  445. end
  446. 1 def log(load_lines=nil)
  447. if new_core?
  448. worker_log = abf_worker_log
  449. Pygments.highlight(worker_log, lexer: 'sh') rescue worker_log
  450. else
  451. I18n.t('layout.build_lists.log.not_available')
  452. end
  453. end
  454. 1 def last_published(testing = false)
  455. 3 BuildList.where(project_id: self.project_id,
  456. save_to_repository_id: self.save_to_repository_id)
  457. .for_platform(self.build_for_platform_id)
  458. .scoped_to_arch(self.arch_id)
  459. 3 .for_status(testing ? BUILD_PUBLISHED_INTO_TESTING : BUILD_PUBLISHED)
  460. .recent
  461. end
  462. 1 def sha1_of_file_store_files
  463. packages.pluck(:sha1).compact | (results || []).map{ |r| r['sha1'] }.compact
  464. end
  465. 1 def cancel_job
  466. if [BUILD_PENDING, RERUN_TESTS].include?(status)
  467. build_canceled
  468. elsif
  469. send_stop_signal
  470. end
  471. true
  472. end
  473. 1 def abf_worker_args
  474. repos = include_repos
  475. include_repos_hash = {}.tap do |h|
  476. Repository.where(id: (repos | (extra_repositories || [])) ).each do |repo|
  477. path, prefix = repo.platform.public_downloads_url(
  478. repo.platform.main? ? nil : build_for_platform.name,
  479. arch.name,
  480. repo.name
  481. ), "#{repo.platform.name}_#{repo.name}_"
  482. h["#{prefix}release"] = insert_token_to_path(path + 'release', repo.platform)
  483. h["#{prefix}updates"] = insert_token_to_path(path + 'updates', repo.platform) if repo.platform.main?
  484. h["#{prefix}testing"] = insert_token_to_path(path + 'testing', repo.platform) if include_testing_subrepository?
  485. end
  486. end
  487. host = EventLog.current_controller.request.host_with_port rescue ::Rosa::Application.config.action_mailer.default_url_options[:host]
  488. BuildList.where(id: extra_build_lists).each do |bl|
  489. path = "#{APP_CONFIG['downloads_url']}/#{bl.save_to_platform.name}/container/"
  490. path << "#{bl.id}/#{bl.arch.name}/#{bl.save_to_repository.name}/release"
  491. include_repos_hash["container_#{bl.id}"] = insert_token_to_path(path, bl.save_to_platform)
  492. end
  493. git_project_address = project.git_project_address user
  494. # git_project_address.gsub!(/^http:\/\/(0\.0\.0\.0|localhost)\:[\d]+/, 'https://abf.rosalinux.ru') unless Rails.env.production?
  495. cmd_params = {
  496. 'PACKAGE' => project.name,
  497. 'GIT_PROJECT_ADDRESS' => git_project_address,
  498. 'GIT_REPO' => git_project_address,
  499. 'COMMIT_HASH' => commit_hash,
  500. 'PROJECT_VERSION' => project_version,
  501. 'USE_EXTRA_TESTS' => use_extra_tests?,
  502. 'SAVE_BUILDROOT' => save_buildroot?,
  503. 'EXTRA_CFG_OPTIONS' => extra_params['cfg_options'],
  504. 'EXTRA_CFG_URPM_OPTIONS' => extra_params['cfg_urpm_options'],
  505. 'EXTRA_BUILD_SRC_RPM_OPTIONS' => extra_params['build_src_rpm'],
  506. 'EXTRA_BUILD_RPM_OPTIONS' => extra_params['build_rpm'],
  507. 'PLATFORM_NAME' => build_for_platform.name,
  508. 'FILE_STORE_ADDR' => APP_CONFIG['file_store_url'].gsub(/\/$/, '')
  509. }
  510. cmd_params.merge!(
  511. 'RERUN_TESTS' => true,
  512. 'PACKAGES' => packages.pluck(:sha1).compact * ' '
  513. ) if rerun_tests?
  514. if use_cached_chroot?
  515. sha1 = build_for_platform.cached_chroot(arch.name)
  516. cmd_params.merge!('CACHED_CHROOT_SHA1' => sha1) if sha1.present?
  517. end
  518. # cmd_params = cmd_params.map{ |k, v| "#{k}='#{v}'" }.join(' ')
  519. {
  520. id: id,
  521. time_living: (build_for_platform.platform_arch_settings.by_arch(arch).first.try(:time_living) || PlatformArchSetting::DEFAULT_TIME_LIVING),
  522. distrib_type: build_for_platform.distrib_type,
  523. cmd_params: cmd_params,
  524. include_repos: include_repos_hash,
  525. platform: {
  526. type: build_for_platform.distrib_type,
  527. name: build_for_platform.name,
  528. arch: arch.name
  529. },
  530. rerun_tests: rerun_tests?,
  531. user: { uname: user.uname, email: user.email }
  532. }
  533. end
  534. 1 def cleanup_packages_from_testing
  535. AbfWorkerService::Base.cleanup_packages_from_testing(
  536. build_for_platform_id,
  537. save_to_repository_id,
  538. id
  539. )
  540. end
  541. 1 def valid_branch_for_publish?
  542. @valid_branch_for_publish ||= begin
  543. save_to_platform.personal? ||
  544. save_to_repository.publish_builds_only_from_branch.blank? ||
  545. ( project_version == save_to_repository.publish_builds_only_from_branch ) ||
  546. project.repo.git.native(:branch, {}, '--contains', commit_hash).
  547. gsub(/\*/, '').split(/\n/).map(&:strip).
  548. include?(save_to_repository.publish_builds_only_from_branch)
  549. end
  550. end
  551. 1 protected
  552. 1 def create_container
  553. Resque.enqueue(BuildLists::CreateContainerJob, id)
  554. end
  555. 1 def remove_container
  556. AbfWorkerService::Container.new(self).destroy! if save_to_platform
  557. end
  558. 1 def abf_worker_priority
  559. mass_build_id ? '' : 'default'
  560. end
  561. 1 def abf_worker_base_queue
  562. 'rpm_worker'
  563. end
  564. 1 def insert_token_to_path(path, platform)
  565. if platform.hidden?
  566. path.gsub(/^http:\/\//, "http://#{user.authentication_token}:@")
  567. else
  568. path
  569. end
  570. end
  571. 1 def notify_users
  572. unless mass_build_id
  573. users = [user, publisher].compact.uniq.select{ |u| u.notifier.can_notify? && u.notifier.new_build? }
  574. # find associated users
  575. users |= project.all_members(:notifier).select do |u|
  576. u.notifier.can_notify? && u.notifier.new_associated_build?
  577. end if project
  578. users.each{ |u| UserMailer.build_list_notification(self, u).deliver }
  579. end
  580. end # notify_users
  581. 1 def build_package(pkg_hash, package_type, prj)
  582. packages.create(pkg_hash) do |p|
  583. p.project = prj
  584. p.platform = save_to_platform
  585. p.package_type = package_type
  586. yield p
  587. end
  588. end
  589. 1 def set_publisher
  590. self.publisher ||= user
  591. save
  592. end
  593. 1 def prepare_extra_repositories
  594. 3 if save_to_platform && save_to_platform.main?
  595. 3 self.extra_repositories = nil
  596. else
  597. self.extra_repositories = PlatformPolicy::Scope.new(user, Repository.joins(:platform)).show.
  598. where(id: extra_repositories).
  599. pluck('repositories.id')
  600. end
  601. end
  602. 1 def prepare_extra_build_lists
  603. 3 if mass_build && mass_build.extra_mass_builds.present?
  604. extra_build_lists << BuildList.where(mass_build_id: mass_build.extra_mass_builds).pluck(:id)
  605. extra_build_lists.flatten!
  606. end
  607. 3 return if extra_build_lists.blank?
  608. bls = BuildListPolicy::Scope.new(user, BuildList).read.
  609. for_extra_build_lists(extra_build_lists, save_to_platform)
  610. if save_to_platform
  611. if save_to_platform.distrib_type == 'rhel'
  612. bls = bls.where('
  613. (build_lists.arch_id = ? AND projects.publish_i686_into_x86_64 is not true) OR
  614. (projects.publish_i686_into_x86_64 is true)
  615. ', arch_id).joins(:project)
  616. else
  617. bls = bls.where(arch_id: arch_id)
  618. end
  619. end
  620. self.extra_build_lists = bls.pluck(Arel.sql('build_lists.id'))
  621. end
  622. 1 def prepare_auto_publish_status
  623. 3 if external_nodes.present?
  624. self.auto_publish_status = AUTO_PUBLISH_STATUS_NONE
  625. end
  626. 3 if auto_publish? && save_to_repository && !save_to_repository.publish_without_qa?
  627. self.auto_publish_status = AUTO_PUBLISH_STATUS_NONE
  628. end
  629. 3 if auto_publish? || auto_publish_into_testing?
  630. 3 self.auto_create_container = false
  631. end
  632. 3 true
  633. end
  634. 1 def prepare_extra_params
  635. 3 if extra_params.present?
  636. params = extra_params.slice(*BuildList::EXTRA_PARAMS)
  637. params.update(params) do |k,v|
  638. v.strip.gsub(I18n.t("activerecord.attributes.build_list.extra_params.#{k}"), '').
  639. gsub(/[^\w\s\-["]'=]/, '')
  640. end
  641. self.extra_params = params.select{ |k,v| v.present? }
  642. end
  643. end
  644. end

app/models/build_list/filter.rb

20.0% lines covered

50 relevant lines. 10 lines covered and 40 lines missed.
    
  1. 1 class BuildList::Filter
  2. 1 PER_PAGE = [25, 50, 100]
  3. 1 attr_reader :options
  4. 1 def initialize(project, user, options = {})
  5. @project, @user = project, user
  6. set_options(options)
  7. end
  8. 1 def find
  9. build_lists = @project ? @project.build_lists : BuildList.all
  10. if @options[:id]
  11. build_lists = build_lists.where(id: @options[:id])
  12. else
  13. build_lists =
  14. case @options[:ownership]
  15. when 'owned'
  16. BuildListPolicy::Scope.new(@user, build_lists).owned
  17. when 'related'
  18. BuildListPolicy::Scope.new(@user, build_lists).related
  19. else
  20. BuildListPolicy::Scope.new(@user, build_lists).everything
  21. end
  22. build_lists = build_lists.scoped_to_new_core(@options[:new_core] == '0' ? nil : true) if @options[:new_core].present?
  23. if @options[:mass_build_id]
  24. build_lists = build_lists.by_mass_build(@options[:mass_build_id] == '-1' ? nil : @options[:mass_build_id])
  25. end
  26. build_lists = build_lists.for_status(@options[:status])
  27. .scoped_to_arch(@options[:arch_id])
  28. .scoped_to_save_platform(@options[:save_to_platform_id])
  29. .scoped_to_build_for_platform(@options[:build_for_platform_id])
  30. .scoped_to_save_to_repository(@options[:save_to_repository_id])
  31. .scoped_to_project_version(@options[:project_version])
  32. .scoped_to_project_name(@options[:project_name])
  33. .for_notified_date_period(@options[:updated_at_start], @options[:updated_at_end])
  34. end
  35. build_lists
  36. end
  37. 1 def respond_to?(name)
  38. return true if @options.has_key?(name)
  39. super
  40. end
  41. 1 def method_missing(name, *args, &block)
  42. @options.has_key?(name) ? @options[name] : super
  43. end
  44. 1 private
  45. 1 def set_options(options)
  46. if options.is_a?(ActionController::Parameters)
  47. options = options.permit([:ownership, :status, :updated_at_start, :updated_at_end, :arch_id,
  48. :save_to_platform_id, :build_for_platform_id, :save_to_repository_id,
  49. :is_circle, :project_version, :id, :project_name, :mass_build_id, :new_core]).to_h
  50. end
  51. @options = HashWithIndifferentAccess.new(options.reverse_merge({
  52. ownership: nil,
  53. status: nil,
  54. updated_at_start: nil,
  55. updated_at_end: nil,
  56. arch_id: nil,
  57. save_to_platform_id: nil,
  58. build_for_platform_id: nil,
  59. save_to_repository_id: nil,
  60. is_circle: nil,
  61. project_version: nil,
  62. id: nil,
  63. project_name: nil,
  64. mass_build_id: nil,
  65. new_core: nil
  66. }))
  67. @options[:ownership] = @options[:ownership].presence || (@project || !@user ? 'everything' : 'owned')
  68. @options[:status] = @options[:status].present? ? @options[:status].to_i : nil
  69. @options[:created_at_start] = build_date_from_params(:created_at_start, @options)
  70. @options[:created_at_end] = build_date_from_params(:created_at_end, @options)
  71. @options[:updated_at_start] = build_date_from_params(:updated_at_start, @options)
  72. @options[:updated_at_end] = build_date_from_params(:updated_at_end, @options)
  73. @options[:project_version] = @options[:project_version].presence
  74. @options[:arch_id] = @options[:arch_id].try(:to_i)
  75. @options[:save_to_platform_id] = @options[:save_to_platform_id].try(:to_i)
  76. @options[:build_for_platform_id] = @options[:build_for_platform_id].try(:to_i)
  77. @options[:save_to_repository_id] = @options[:save_to_repository_id].try(:to_i)
  78. @options[:is_circle] = @options[:is_circle].present? ? @options[:is_circle] == "1" : nil
  79. @options[:id] = @options[:id].presence
  80. @options[:project_name] = @options[:project_name].presence
  81. @options[:mass_build_id] = @options[:mass_build_id].presence
  82. @options[:new_core] = @options[:new_core].presence
  83. end
  84. 1 def build_date_from_params(field_name, params)
  85. return nil if params[field_name].blank?
  86. params[field_name].strip!
  87. return Date.parse(params[field_name]) if params[field_name] =~ /\A\d{2}\/\d{2}\/\d{4}\z/
  88. return Time.at(params[field_name].to_i) if params[field_name] =~ /\A\d+\z/
  89. nil
  90. end
  91. end

app/models/build_list/item.rb

50.0% lines covered

18 relevant lines. 9 lines covered and 9 lines missed.
    
  1. 1 class BuildList::Item < ActiveRecord::Base
  2. 1 belongs_to :build_list, touch: true
  3. # attr_protected :build_list_id
  4. 1 GIT_ERROR = 5
  5. 1 STATUSES = [BuildList::SUCCESS, BuildList::BUILD_ERROR, BuildList::BUILD_STARTED, GIT_ERROR, BuildList::BUILD_CANCELED] # BuildList::DEPENDENCIES_ERROR
  6. HUMAN_STATUSES = {
  7. 1 nil => :unknown,
  8. GIT_ERROR => :git_error,
  9. # BuildList:DEPENDENCIES_ERROR: :dependencies_error,
  10. BuildList::SUCCESS => :success,
  11. BuildList::BUILD_STARTED => :build_started,
  12. BuildList::BUILD_ERROR => :build_error,
  13. BuildList::BUILD_CANCELED => :build_canceled
  14. }
  15. 1 scope :recent, -> { order("#{table_name}.level ASC, #{table_name}.name ASC") }
  16. 1 def self.group_by_level
  17. groups = []
  18. current_level = -1
  19. all.recent.find_each do |item|
  20. groups << [] if current_level < item.level
  21. groups.last << item
  22. current_level = item.level
  23. end
  24. groups
  25. end
  26. 1 def self.human_status(status)
  27. I18n.t("layout.build_lists.items.statuses.#{HUMAN_STATUSES[status]}")
  28. end
  29. 1 def human_status
  30. self.class.human_status(status)
  31. end
  32. end

app/models/build_list/package.rb

56.1% lines covered

41 relevant lines. 23 lines covered and 18 lines missed.
    
  1. 1 class BuildList::Package < ActiveRecord::Base
  2. 1 PACKAGE_TYPES = %w(source binary)
  3. 1 belongs_to :build_list, touch: true
  4. 1 belongs_to :project
  5. 1 belongs_to :platform
  6. 1 serialize :dependent_packages, Array
  7. 1 validates :build_list, :build_list_id, :project, :project_id,
  8. :platform, :platform_id, :fullname,
  9. :package_type, :name, :release, :version,
  10. presence: true
  11. 1 validates :package_type, inclusion: PACKAGE_TYPES
  12. 1 validates :sha1, presence: true, if: Proc.new { |p| p.build_list.new_core? }
  13. 1 default_scope { order("lower(#{table_name}.name) ASC, length(#{table_name}.name) ASC") }
  14. # Fetches only actual (last publised) packages.
  15. 1 scope :actual, -> { where(actual: true) }
  16. 1 scope :by_platform, ->(platform) { where(platform_id: platform) }
  17. 1 scope :by_name, ->(name) { where(name: name) }
  18. 1 scope :by_package_type, ->(type) { where(package_type: type) }
  19. 1 scope :like_name, ->(name) { where("#{table_name}.name ILIKE ?", "%#{name}%") if name.present? }
  20. 1 before_create :set_epoch
  21. 1 def assignee
  22. project.maintainer
  23. end
  24. # Comparison between versions
  25. # @param [BuildList::Package] other
  26. # @return [Number] -1 if +other+ is greater than, 0 if +other+ is equal to,
  27. # and +1 if other is less than version.
  28. 1 def rpmvercmp(other)
  29. RPM.compareVREs to_vre_epoch_zero, other.to_vre_epoch_zero
  30. end
  31. 1 def self.by_repository(repository, &block)
  32. # find_each will batch the results instead of getting all in one go
  33. actual.where(
  34. build_lists: {save_to_repository_id: repository}
  35. ).joins(build_list: :save_to_repository).includes(project: :maintainer).find_each do |package|
  36. yield package
  37. end
  38. end
  39. # Public: Set dependent_packages.
  40. 1 def dependent_packages=(v)
  41. v = v.to_s.split(/\s/).select(&:present?) if v.is_a?(String)
  42. write_attribute :dependent_packages, v
  43. end
  44. 1 protected
  45. 1 def set_epoch
  46. self.epoch = nil if epoch.blank? || epoch == 0
  47. end
  48. # String representation in the form "e:v-r"
  49. # @return [String]
  50. # @note The epoch is included always. As 0 if not present
  51. 1 def to_vre_epoch_zero
  52. res = []
  53. if epoch.present?
  54. res << epoch.to_s
  55. else
  56. res << '0'
  57. end
  58. if version.present?
  59. res << version.to_s
  60. else
  61. res << ''
  62. end
  63. if release.present?
  64. res << release.to_s
  65. else
  66. res << ''
  67. end
  68. res
  69. end
  70. end

app/models/collaborator.rb

39.53% lines covered

86 relevant lines. 34 lines covered and 52 lines missed.
    
  1. 1 class Collaborator
  2. 1 include ActiveModel::Conversion
  3. 1 include ActiveModel::Validations
  4. 1 include ActiveModel::Serializers::JSON
  5. 1 extend ActiveModel::Naming
  6. 1 attr_accessor :role, :actor, :project, :relation
  7. 1 attr_reader :id, :actor_id, :actor_type, :actor_name, :project_id
  8. 1 delegate :new_record?, to: :relation
  9. 1 class << self
  10. 1 def find_by_project(project)
  11. res = []
  12. project.relations.each do |r|
  13. res << from_relation(r) unless project.owner_id == r.actor_id and project.owner_type == r.actor_type
  14. end
  15. return res
  16. end
  17. 1 def find(id)
  18. return self.from_relation(Relation.find(id)) || nil
  19. end
  20. 1 def create(args)
  21. c = self.new(args)
  22. return c.save ? c : false
  23. end
  24. 1 def create!(args)
  25. c = self.new(args)
  26. c.save!
  27. return c
  28. end
  29. end
  30. 1 def initialize(args = {})
  31. return false if args.blank?
  32. args.to_options!
  33. acc_options = args.select{ |(k, v)| k.in? [:actor, :project, :relation] }
  34. acc_options.each_pair do |name, value|
  35. send("#{name}=", value)
  36. end
  37. if args[:project_id].present?
  38. @project = Project.find(args[:project_id])
  39. end
  40. if args[:actor_id].present? and args[:actor_type].present?
  41. @actor = args[:actor_type].classify.constantize.find(args[:actor_id])
  42. end
  43. relation.role = args[:role] if args[:role].present? #if @relation.present? and args[:role].present?
  44. end
  45. 1 def update(attributes, options = {})
  46. attributes.each_pair do |k, v|
  47. send("#{k}=", v)
  48. end
  49. save
  50. end
  51. 1 def relation=(model)
  52. @relation = model
  53. @actor = @relation.actor
  54. @project = @relation.target
  55. end
  56. 1 def id
  57. relation.try(:id)
  58. end
  59. 1 def actor_id
  60. @actor.try(:id)
  61. end
  62. 1 def actor_type
  63. @actor.class.to_s.underscore
  64. end
  65. 1 def actor_name
  66. if @actor.present?
  67. @actor.instance_of?(User) ? "#{@actor.uname}#{ @actor.try(:name) and !@actor.name.empty? ? " (#{@actor.name})" : ''}" : @actor.uname
  68. else
  69. nil
  70. end
  71. end
  72. 1 def actor_uname
  73. @actor.uname
  74. end
  75. 1 def project_id
  76. @project.try(:id)
  77. end
  78. 1 def role
  79. relation.try(:role)
  80. end
  81. 1 def role=(arg)
  82. relation.role = arg
  83. end
  84. 1 def save
  85. relation.try(:save)
  86. end
  87. 1 def save!
  88. relation.try(:save!)
  89. end
  90. 1 def destroy
  91. relation.try(:destroy)
  92. @actor.check_assigned_issues @project
  93. end
  94. 1 def attributes
  95. %w{ id actor_id actor_type actor_name project_id role}.inject({}) do |h, e|
  96. h.merge(e => send(e))
  97. end
  98. end
  99. 1 def persisted?
  100. false
  101. end
  102. 1 protected
  103. 1 class << self
  104. 1 def from_relation(relation)
  105. return nil unless relation.present?
  106. return self.new(relation: relation)
  107. end
  108. end
  109. 1 def relation
  110. return @relation if @relation.present? and @relation.actor == @actor and @relation.target == @project
  111. if @actor.present? and @project.present?
  112. @relation = Relation.by_actor(@actor).by_target(@project).limit(1).first
  113. @relation ||= Relation.new(:actor_id => @actor.id, :actor_type => @actor.class.to_s,
  114. target_id: @project.id, target_type: 'Project')
  115. else
  116. @relation = Relation.new
  117. @relation.actor = @actor
  118. @relation.target = @project
  119. end
  120. @relation
  121. end
  122. end
  123. 1 Collaborator.include_root_in_json = false

app/models/comment.rb

24.41% lines covered

127 relevant lines. 31 lines covered and 96 lines missed.
    
  1. 1 class Comment < ActiveRecord::Base
  2. 1 include Feed::Comment
  3. # regexp take from http://code.google.com/p/concerto-platform/source/browse/v3/cms/lib/CodeMirror/mode/gfm/gfm.js?spec=svn861&r=861#71
  4. # User/Project#Num
  5. # User#Num
  6. # #Num
  7. 1 ISSUES_REGEX = /(?:[a-zA-Z0-9\-_]*\/)?(?:[a-zA-Z0-9\-_]*)?#[0-9]+/
  8. 1 belongs_to :user
  9. 1 belongs_to :project
  10. 1 serialize :data
  11. 1 validates :body, :user, :commentable_id, :commentable_type, :project_id, presence: true
  12. 1 validates :body, length: { maximum: 10000 }
  13. 1 scope :for_commit, ->(c) { where(commentable_id: c.id.hex, commentable_type: c.class) }
  14. 1 default_scope { order(:created_at) }
  15. 1 before_save :touch_commentable
  16. 1 after_create :subscribe_on_reply, unless: ->(c) { c.commit_comment? }
  17. 1 after_create :subscribe_users
  18. 1 def commentable
  19. if commit_comment?
  20. project.repo.commit(Comment.hex_to_commit_hash commentable_id)
  21. else
  22. commentable_type.constantize.find_by_id(commentable_id)
  23. end
  24. end
  25. 1 def commentable=(c)
  26. if self.class.commit_comment?(c.class)
  27. self.commentable_id = c.id.hex
  28. else
  29. self.commentable_id = c.id
  30. end
  31. self.commentable_type = c.class.name
  32. end
  33. 1 def self.commit_comment?(class_name)
  34. class_name.to_s == 'Grit::Commit'
  35. end
  36. 1 def commit_comment?
  37. self.class.commit_comment?(commentable_type)
  38. end
  39. 1 def self.issue_comment?(class_name)
  40. class_name.to_s == 'Issue'
  41. end
  42. 1 def issue_comment?
  43. self.class.issue_comment?(commentable_type)
  44. end
  45. 1 def own_comment?(user)
  46. user_id == user.id
  47. end
  48. 1 def actual_inline_comment?(diff = nil, force = false)
  49. unless force
  50. raise "This is not inline comment!" if data.blank? # for debug
  51. return data[:actual] unless data[:actual].nil?
  52. return false if diff.nil?
  53. end
  54. return data[:actual] = true if commentable_type == 'Grit::Commit'
  55. filepath, line_number = data[:path], data[:line]
  56. diff_path = (diff || commentable.show ).select {|d| d.a_path == data[:path]}
  57. comment_line = data[:line].to_i
  58. # NB! also dont create a comment to the diff header
  59. return data[:actual] = false if diff_path.blank? || comment_line == 0
  60. res, ind = true, 0
  61. diff_path[0].diff.each_line do |line|
  62. if self.persisted? && (comment_line-2..comment_line+2).include?(ind) && data.try('[]', "line#{ind-comment_line}") != line.chomp
  63. break res = false
  64. end
  65. ind = ind + 1
  66. end
  67. if ind < comment_line
  68. return data[:actual] = false
  69. else
  70. return data[:actual] = res
  71. end
  72. end
  73. 1 def inline_diff
  74. data[:strings] + data['line0']
  75. end
  76. 1 def pull_comment?
  77. commentable.is_a?(Issue) && commentable.pull_request.present?
  78. end
  79. 1 def set_additional_data params
  80. return true if params[:path].blank? && params[:line].blank? # not inline comment
  81. if params[:in_reply].present? && reply = Comment.where(id: params[:in_reply]).first
  82. self.data = reply.data
  83. return true
  84. end
  85. self.data = {path: params[:path], line: params[:line]}
  86. return actual_inline_comment?(nil, true) if commentable.is_a?(Grit::Commit)
  87. if commentable.is_a?(Issue) && pull = commentable.pull_request
  88. diff_path = pull.diff.select {|d| d.a_path == params[:path]}
  89. return false unless actual_inline_comment?(pull.diff, true)
  90. comment_line, line_number, strings = params[:line].to_i, -1, []
  91. diff_path[0].diff.each_line do |line|
  92. line_number = line_number.succ
  93. # Save 2 lines above and bottom of the diff comment line
  94. break if line_number > comment_line + 2
  95. if (comment_line-2..comment_line+2).include? line_number
  96. data["line#{line_number-comment_line}"] = line.chomp
  97. end
  98. # Save lines from the closest header for rendering in the discussion
  99. if line_number < comment_line
  100. # Header is the line like "@@ -47,9 +50,8 @@ def initialize(user)"
  101. if line =~ Diff::Display::Unified::Generator::LINE_NUM_RE
  102. strings = [line]
  103. else
  104. strings << line
  105. end
  106. end
  107. end
  108. ## Bug with numbers of diff lines, now store all diff
  109. data[:strings] = strings.join
  110. # Limit stored diff to 10 lines (see inline_diff)
  111. #data[:strings] = ((strings.count) <= 9 ? strings : [strings[0]] + strings.last(8)).join
  112. ##
  113. data[:view_path] = h(diff_path[0].renamed_file ? "#{diff_path[0].a_path.rtruncate 60} -> #{diff_path[0].b_path.rtruncate 60}" : diff_path[0].a_path.rtruncate(120))
  114. end
  115. return true
  116. end
  117. 1 def self.create_link_on_issues_from_item item, commits = nil
  118. linker = item.user
  119. case
  120. when item.is_a?(GitHook)
  121. elements = commits
  122. opts = {}
  123. when item.is_a?(Issue)
  124. elements = [[item, item.title], [item, item.body]]
  125. opts = {created_from_issue_id: item.id}
  126. when item.commentable_type == 'Issue'
  127. elements = [[item, item.body]]
  128. opts = {created_from_issue_id: item.commentable_id}
  129. when item.commentable_type == 'Grit::Commit'
  130. elements = [[item, item.body]]
  131. opts = {created_from_commit_hash: item.commentable_id}
  132. else
  133. raise "Unsupported item type #{item.class.name}!"
  134. end
  135. elements.each do |element|
  136. element[1].scan(ISSUES_REGEX).each do |hash|
  137. issue = Issue.find_by_hash_tag hash, linker, item.project
  138. next unless issue
  139. # dont create link to the same issue
  140. next if opts[:created_from_issue_id] == issue.id
  141. opts = {created_from_commit_hash: element[0].hex} if item.is_a?(GitHook)
  142. # dont create duplicate link to issue
  143. next if Comment.find_existing_automatic_comment issue, opts
  144. # dont create link to outdated commit
  145. next if item.is_a?(GitHook) && !item.project.repo.commit(element[0])
  146. comment = linker.comments.new body: 'automatic comment'
  147. comment.commentable, comment.project, comment.automatic = issue, issue.project, true
  148. comment.data = {from_project_id: item.project.id}
  149. if opts[:created_from_commit_hash]
  150. comment.created_from_commit_hash = opts[:created_from_commit_hash]
  151. elsif opts[:created_from_issue_id]
  152. comment.data.merge!(comment_id: item.id) if item.is_a? Comment
  153. comment.created_from_issue_id = opts[:created_from_issue_id]
  154. else
  155. raise 'Unsupported opts for automatic comment!'
  156. end
  157. comment.save
  158. end
  159. end
  160. end
  161. 1 def self.hex_to_commit_hash hex
  162. # '079d'.hex.to_s(16) => "79d"
  163. t = hex.to_s(16)
  164. '0'*(40-t.length) << t # commit hash has 40-character
  165. end
  166. 1 protected
  167. 1 def touch_commentable
  168. commentable.touch unless commit_comment?
  169. end
  170. 1 def subscribe_on_reply
  171. commentable.subscribes.where(user_id: user_id).first_or_create
  172. end
  173. 1 def subscribe_users
  174. if issue_comment?
  175. commentable.subscribes.create(user: user) if !commentable.subscribes.exists?(user_id: user.id)
  176. elsif commit_comment?
  177. recipients = project.all_members
  178. recipients << user << User.find_by(email: commentable.try(:committer).try(:email)) # commentor and committer
  179. recipients.compact.uniq.each do |user|
  180. options = {project_id: project.id, subscribeable_id: commentable_id, subscribeable_type: commentable.class.name, user_id: user.id}
  181. Subscribe.subscribe_to_commit(options) if Subscribe.subscribed_to_commit?(project, user, commentable)
  182. end
  183. end
  184. end
  185. 1 def self.find_existing_automatic_comment issue, opts
  186. find_dup = opts.merge(automatic: true, commentable_type: issue.class.name,
  187. commentable_id: issue.id)
  188. Comment.exists? find_dup
  189. end
  190. end

app/models/concerns/abf_worker_methods.rb

44.12% lines covered

34 relevant lines. 15 lines covered and 19 lines missed.
    
  1. 1 module AbfWorkerMethods
  2. 1 extend ActiveSupport::Concern
  3. 1 MASS_BUILDS_SET = 'abf-worker::mass-builds'
  4. 1 USER_BUILDS_SET = 'abf-worker::user-builds'
  5. 1 module ClassMethods
  6. 1 def log_server
  7. @log_server ||= Redis.new(url: ENV['REDIS_URL'])
  8. end
  9. end
  10. 1 def abf_worker_log
  11. (self.class.log_server.get(service_queue) || I18n.t('layout.build_lists.log.not_available')).truncate(40000)
  12. end
  13. 1 def add_job_to_abf_worker_queue
  14. Resque.push(
  15. worker_queue_with_priority,
  16. 'class' => worker_queue_class,
  17. 'args' => [abf_worker_args]
  18. )
  19. end
  20. 1 def cancel_job
  21. if destroy_from_resque_queue == 1
  22. build_canceled
  23. elsif
  24. send_stop_signal
  25. end
  26. true
  27. end
  28. 1 def destroy_from_resque_queue
  29. Resque::Job.destroy(
  30. worker_queue_with_priority,
  31. worker_queue_class,
  32. abf_worker_args
  33. )
  34. end
  35. 1 def worker_queue_with_priority(prefix = true)
  36. queue = ''
  37. if prefix && is_a?(BuildList)
  38. if mass_build_id
  39. queue << "mass_build_#{mass_build_id}_"
  40. else
  41. queue << "user_build_#{user_id}_"
  42. end
  43. end
  44. queue << abf_worker_base_queue
  45. queue << '_' << abf_worker_priority if abf_worker_priority.present?
  46. queue
  47. end
  48. 1 def worker_queue_class
  49. "AbfWorker::#{abf_worker_base_queue.classify}#{abf_worker_priority.capitalize}"
  50. end
  51. 1 private
  52. 1 def send_stop_signal
  53. Redis.current.setex(
  54. "#{service_queue}::live-inspector",
  55. 240, # Data will be removed from Redis after 240 sec.
  56. 'USR1' # Immediately kill child but don't exit
  57. )
  58. end
  59. 1 def service_queue
  60. "abfworker::#{abf_worker_base_queue.gsub(/\_/, '-')}-#{id}"
  61. end
  62. end

app/models/concerns/acts_like_member.rb

75.0% lines covered

16 relevant lines. 12 lines covered and 4 lines missed.
    
  1. 1 module ActsLikeMember
  2. 1 extend ActiveSupport::Concern
  3. 1 included do
  4. 2 scope :not_member_of, ->(item) {
  5. where("
  6. #{table_name}.id NOT IN (
  7. SELECT relations.actor_id
  8. FROM relations
  9. WHERE (
  10. relations.actor_type = '#{self.to_s}'
  11. AND relations.target_type = '#{item.class.to_s}'
  12. AND relations.target_id = #{item.id}
  13. )
  14. )
  15. ")
  16. }
  17. 2 scope :search_order, -> { order("CHAR_LENGTH(#{table_name}.uname) ASC") }
  18. 2 scope :without_ids, ->(a) { where("#{table_name}.id NOT IN (?)", a) }
  19. 14 scope :by_uname, ->(n) { where("#{table_name}.uname ILIKE ?", n) }
  20. 2 scope :search_like, ->(q) { by_uname("%#{q.to_s.strip}%") }
  21. end
  22. 1 def to_param
  23. uname
  24. end
  25. 1 module ClassMethods
  26. 1 def find_by_insensitive_uname(uname)
  27. find_by(uname: uname) || by_uname(uname).first
  28. end
  29. 1 def find_by_insensitive_uname!(uname)
  30. find_by_insensitive_uname(uname) or raise ActiveRecord::RecordNotFound
  31. end
  32. end
  33. end

app/models/concerns/autostart.rb

85.71% lines covered

14 relevant lines. 12 lines covered and 2 lines missed.
    
  1. 1 module Autostart
  2. 1 extend ActiveSupport::Concern
  3. 1 ONCE_A_12_HOURS = 0
  4. 1 ONCE_A_DAY = 1
  5. 1 ONCE_A_WEEK = 2
  6. 1 AUTOSTART_STATUSES = [ONCE_A_12_HOURS, ONCE_A_DAY, ONCE_A_WEEK]
  7. HUMAN_AUTOSTART_STATUSES = {
  8. 1 ONCE_A_12_HOURS => :once_a_12_hours,
  9. ONCE_A_DAY => :once_a_day,
  10. ONCE_A_WEEK => :once_a_week
  11. }
  12. 1 included do
  13. 2 validates :autostart_status, numericality: true,
  14. inclusion: {in: AUTOSTART_STATUSES}, allow_blank: true
  15. end
  16. 1 def human_autostart_status
  17. self.class.human_autostart_status(autostart_status)
  18. end
  19. 1 module ClassMethods
  20. 1 def human_autostart_status(autostart_status)
  21. I18n.t("layout.products.autostart_statuses.#{HUMAN_AUTOSTART_STATUSES[autostart_status]}")
  22. end
  23. end
  24. end

app/models/concerns/build_list_observer.rb

65.0% lines covered

20 relevant lines. 13 lines covered and 7 lines missed.
    
  1. 1 module BuildListObserver
  2. 1 extend ActiveSupport::Concern
  3. 1 included do
  4. 1 before_update :update_average_build_time
  5. 1 before_update :update_statistic
  6. end
  7. 1 private
  8. 1 def update_statistic
  9. 3 Statistic.statsd_increment(
  10. activity_at: Time.now,
  11. key: "#{Statistic::KEY_BUILD_LIST}.#{status}",
  12. project_id: project_id,
  13. user_id: user_id,
  14. 3 ) if status_changed?
  15. end
  16. 1 def update_average_build_time
  17. 3 if status_changed?
  18. 3 self.started_at = Time.now if status == self.class::BUILD_STARTED
  19. 3 if [self.class::BUILD_ERROR,
  20. self.class::SUCCESS,
  21. self.class::BUILD_CANCELING,
  22. self.class::TESTS_FAILED,
  23. self.class::BUILD_CANCELED].include? status
  24. # stores time interval beetwin build start and finish in seconds
  25. self.duration = current_duration if self.started_at
  26. if status == self.class::SUCCESS
  27. # Update project average build time
  28. begin
  29. statistic = project.project_statistics.where(arch_id: arch_id).first_or_create
  30. rescue ActiveRecord::RecordNotUnique
  31. retry
  32. end
  33. build_count = statistic.build_count.to_i
  34. new_av_time = ( statistic.average_build_time * build_count + duration.to_i ) / ( build_count + 1 )
  35. statistic.update(average_build_time: new_av_time, build_count: build_count + 1)
  36. end
  37. end
  38. end
  39. end
  40. end

app/models/concerns/commit_and_version.rb

78.95% lines covered

19 relevant lines. 15 lines covered and 4 lines missed.
    
  1. 1 module CommitAndVersion
  2. 1 extend ActiveSupport::Concern
  3. 1 included do
  4. 2 validate -> {
  5. 6 if project && (commit_hash.blank? || project.repo.commit(commit_hash).blank?)
  6. errors.add :commit_hash, I18n.t('flash.build_list.wrong_commit_hash', commit_hash: commit_hash)
  7. end
  8. }
  9. 2 before_validation :set_commit_and_version
  10. 2 before_create :set_last_published_commit
  11. end
  12. 1 protected
  13. 1 def set_commit_and_version
  14. 6 if project && project_version.present? && commit_hash.blank?
  15. self.commit_hash = project.repo.commits(project_version).try(:first).try(:id)
  16. 6 elsif project_version.blank? && commit_hash.present?
  17. self.project_version = commit_hash
  18. end
  19. end
  20. 1 def set_last_published_commit
  21. 3 return unless self.respond_to? :last_published_commit_hash # product?
  22. 3 last_commit = self.last_published.first.try :commit_hash
  23. 3 if last_commit && self.project.repo.commit(last_commit).present? # commit(nil) is not nil!
  24. self.last_published_commit_hash = last_commit
  25. end
  26. end
  27. end

app/models/concerns/default_branchable.rb

100.0% lines covered

4 relevant lines. 4 lines covered and 0 lines missed.
    
  1. 1 module DefaultBranchable
  2. 1 extend ActiveSupport::Concern
  3. 1 included do
  4. 3 validates :default_branch,
  5. length: { maximum: 100 }
  6. end
  7. end

app/models/concerns/empty_metadata.rb

71.43% lines covered

7 relevant lines. 5 lines covered and 2 lines missed.
    
  1. 1 module EmptyMetadata
  2. 1 extend ActiveSupport::Concern
  3. 1 included do
  4. 2 after_create :create_empty_metadata
  5. end
  6. 1 def create_empty_metadata
  7. return if is_a?(Platform) && ( personal? || hidden? )
  8. Resque.enqueue(CreateEmptyMetadataJob, self.class.name, id)
  9. end
  10. end

app/models/concerns/event_loggable.rb

62.5% lines covered

16 relevant lines. 10 lines covered and 6 lines missed.
    
  1. 1 module EventLoggable
  2. 1 extend ActiveSupport::Concern
  3. 1 included do
  4. 7 after_create :log_creation_event
  5. 7 after_destroy :log_destroying_event
  6. end
  7. 1 private
  8. 1 def log_creation_event
  9. 54 ActiveSupport::Notifications.instrument(self.class.name, eventable: self)
  10. end
  11. 1 def log_before_update
  12. case self.class.to_s
  13. when 'BuildList'
  14. if status_changed? and [BuildList::BUILD_CANCELED, BuildList::BUILD_PUBLISHED].include?(status)
  15. ActiveSupport::Notifications.instrument("event_log.observer", eventable: self)
  16. end
  17. when 'Platform'
  18. if self.visibility_changed?
  19. ActiveSupport::Notifications.instrument "event_log.observer", eventable: self,
  20. message: I18n.t("activeself.attributes.platform.visibility_types.#{visibility}")
  21. end
  22. end
  23. end
  24. 1 def log_destroying_event
  25. ActiveSupport::Notifications.instrument(self.class.name, eventable: self)
  26. end
  27. end

app/models/concerns/external_nodable.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. 1 module ExternalNodable
  2. 1 extend ActiveSupport::Concern
  3. 1 EXTERNAL_NODES = %w(owned everything)
  4. 1 included do
  5. 3 validates :external_nodes,
  6. inclusion: { in: EXTERNAL_NODES },
  7. allow_blank: true
  8. end
  9. end

app/models/concerns/feed/build_list.rb

70.0% lines covered

10 relevant lines. 7 lines covered and 3 lines missed.
    
  1. 1 module Feed::BuildList
  2. 1 extend ActiveSupport::Concern
  3. 1 included do
  4. 1 after_update :build_list_notifications
  5. end
  6. 1 private
  7. 1 def build_list_notifications
  8. 3 if mass_build.blank? && ( # Do not show mass build activity in activity feeds
  9. status_changed? && [
  10. BuildList::BUILD_PENDING,
  11. BuildList::BUILD_PUBLISHED,
  12. BuildList::SUCCESS,
  13. BuildList::BUILD_ERROR,
  14. BuildList::FAILED_PUBLISH,
  15. BuildList::TESTS_FAILED
  16. ].include?(status)
  17. )
  18. updater = publisher || user
  19. (project.all_members | [publisher]).compact.each do |recipient|
  20. ActivityFeed.create(
  21. user: recipient,
  22. kind: 'build_list_notification',
  23. project_owner: project.owner_uname,
  24. project_name: project.name,
  25. creator_id: updater.id,
  26. data: {
  27. build_list_id: id,
  28. status: status,
  29. updated_at: updated_at,
  30. project_id: project_id,
  31. creator_name: updater.name,
  32. creator_email: updater.email
  33. }
  34. )
  35. end
  36. end
  37. end
  38. end

app/models/concerns/feed/comment.rb

30.77% lines covered

26 relevant lines. 8 lines covered and 18 lines missed.
    
  1. 1 module Feed::Comment
  2. 1 extend ActiveSupport::Concern
  3. 1 included do
  4. 1 after_commit :new_comment_notifications, on: :create
  5. # dont remove outdated issues link
  6. 1 after_update -> { Comment.create_link_on_issues_from_item(self) }
  7. end
  8. 1 private
  9. 1 def new_comment_notifications
  10. return if automatic?
  11. if issue_comment?
  12. commentable.subscribes.each do |subscribe|
  13. if can_notify_on_new_comment?(subscribe)
  14. UserMailer.new_comment_notification(self, subscribe.user_id).deliver unless own_comment?(subscribe.user)
  15. ActivityFeed.create(
  16. user_id: subscribe.user_id,
  17. kind: 'new_comment_notification',
  18. project_owner: project.owner_uname,
  19. project_name: project.name,
  20. creator_id: user_id,
  21. data: {
  22. creator_name: user.name,
  23. creator_email: user.email,
  24. comment_body: body.truncate(100, omission: '…'),
  25. issue_title: commentable.title,
  26. issue_serial_id: commentable.serial_id,
  27. project_id: commentable.project.id,
  28. comment_id: id
  29. }
  30. )
  31. end
  32. end
  33. elsif commit_comment?
  34. Subscribe.comment_subscribes(self).where(status: true).each do |subscribe|
  35. next if !subscribe.user_id
  36. if subscribe.user.notifier.can_notify && !own_comment?(subscribe.user)
  37. ( (subscribe.project.owner?(subscribe.user) && subscribe.user.notifier.new_comment_commit_repo_owner) ||
  38. (subscribe.user.commentor?(self.commentable) && subscribe.user.notifier.new_comment_commit_commentor) ||
  39. (subscribe.user.committer?(self.commentable) && subscribe.user.notifier.new_comment_commit_owner) )
  40. UserMailer.new_comment_notification(self, subscribe.user_id).deliver
  41. end
  42. ActivityFeed.create(
  43. user_id: subscribe.user_id,
  44. kind: 'new_comment_commit_notification',
  45. project_owner: project.owner_uname,
  46. project_name: project.name,
  47. creator_id: user_id,
  48. data: {
  49. creator_name: user.name,
  50. creator_email: user.email,
  51. comment_body: body.truncate(100, omission: '…'),
  52. commit_message: commentable.message.truncate(70, omission: '…'),
  53. commit_id: commentable.id,
  54. project_id: project.id,
  55. comment_id: id
  56. }
  57. )
  58. end
  59. end
  60. Comment.create_link_on_issues_from_item(self)
  61. end
  62. 1 def can_notify_on_new_comment?(subscribe)
  63. notifier = SettingsNotifier.find_by user_id: subscribe.user_id
  64. notifier && notifier.new_comment && notifier.can_notify
  65. end
  66. end

app/models/concerns/feed/git.rb

5.56% lines covered

36 relevant lines. 2 lines covered and 34 lines missed.
    
  1. 1 module Feed::Git
  2. 1 def self.create_notifications(record)
  3. case record.class.to_s
  4. when 'GitHook'
  5. return unless record.project
  6. PullRequest.where("from_project_id = ? OR to_project_id = ?", record.project, record.project).needed_checking.each {|pull| pull.check}
  7. record.project.hooks.each{ |h| h.receive_push(record) }
  8. change_type = record.change_type
  9. branch_name = record.refname.split('/').last
  10. if change_type == 'delete'
  11. kind = 'git_delete_branch_notification'
  12. options = {project_id: record.project.id, branch_name: branch_name, change_type: change_type}
  13. else
  14. if record.message # online update
  15. last_commits, commits = [[record.newrev, record.message.truncate(70, omission: '…')]], []
  16. all_commits = last_commits
  17. else
  18. commits = record.project.repo.commits_between(record.oldrev, record.newrev)
  19. all_commits = commits.collect { |commit| [commit.sha, commit.message.truncate(70, omission: '…')] }
  20. last_commits = all_commits.last(3).reverse
  21. end
  22. kind = 'git_new_push_notification'
  23. options = {project_id: record.project.id, last_commits: last_commits,
  24. branch_name: branch_name, change_type: change_type}
  25. if commits.count > 3
  26. commits = commits[0...-3]
  27. options.merge!({other_commits_count: commits.count, other_commits: "#{commits[0].sha[0..9]}...#{commits[-1].sha[0..9]}"})
  28. end
  29. if all_commits.count > 0
  30. Statistic.statsd_increment(
  31. activity_at: Time.now,
  32. key: Statistic::KEY_COMMIT,
  33. project_id: record.project.id,
  34. user_id: record.user.id,
  35. counter: all_commits.count
  36. )
  37. Comment.create_link_on_issues_from_item(record, all_commits)
  38. end
  39. end
  40. options.merge!({creator_name: record.user.name, creator_email: record.user.email}) if record.user
  41. options_for_mail = options.merge(project_owner: record.project.owner_uname,
  42. project_name: record.project.name)
  43. record.project.all_members.each do |recipient|
  44. ActivityFeed.create!(
  45. user: recipient,
  46. kind: kind,
  47. project_owner: record.project.owner_uname,
  48. project_name: record.project.name,
  49. creator_id: record.user.id,
  50. data: options
  51. )
  52. next if record.user && record.user.id == recipient.id
  53. if recipient.notifier.can_notify && recipient.notifier.update_code
  54. UserMailer.send(kind, recipient, options_for_mail).deliver
  55. end
  56. end
  57. when 'Hash' # 'Gollum::Committer'
  58. actor = User.find_by! uname: record[:actor_name]
  59. project = Project.find record[:project_id]
  60. project.all_members.each do |recipient|
  61. ActivityFeed.create!(
  62. user: recipient,
  63. kind: 'wiki_new_commit_notification',
  64. project_owner: project.owner_uname,
  65. project_name: project.name,
  66. creator_id: actor.id,
  67. data: {creator_name: actor.name, creator_email: actor.email,
  68. project_id: project.id, commit_sha: record[:commit_sha]}
  69. )
  70. end
  71. end
  72. end
  73. end

app/models/concerns/feed/issue.rb

46.15% lines covered

26 relevant lines. 12 lines covered and 14 lines missed.
    
  1. 1 module Feed::Issue
  2. 1 extend ActiveSupport::Concern
  3. 1 included do
  4. 1 after_commit :new_issue_notifications, on: :create
  5. 1 after_commit :send_assign_notifications, on: :create, if: ->(i) { i.assignee }
  6. 1 after_update :send_assign_notifications
  7. 1 after_commit :send_hooks, on: :create
  8. 1 after_update -> { send_hooks(:update) }, if: ->(i) { i.previous_changes['status'].present? }
  9. end
  10. 1 private
  11. 1 def new_issue_notifications
  12. return unless user
  13. collect_recipients.each do |recipient|
  14. if user_id != recipient.id && recipient.notifier.can_notify &&
  15. recipient.notifier.new_issue && assignee_id != recipient.id
  16. UserMailer.new_issue_notification(id, recipient.id).deliver
  17. end
  18. ActivityFeed.create(
  19. user: recipient,
  20. kind: 'new_issue_notification',
  21. project_owner: project.owner_uname,
  22. project_name: project.name,
  23. creator_id: user_id,
  24. data: {
  25. creator_name: user.name,
  26. creator_email: user.email,
  27. issue_serial_id: serial_id,
  28. issue_title: title,
  29. project_id: project.id
  30. }
  31. )
  32. end
  33. ::Comment.create_link_on_issues_from_item(self)
  34. end
  35. 1 def send_assign_notifications
  36. return if @skip_assign_notifications
  37. @skip_assign_notifications = true
  38. if assignee_id && (new_pull_request || saved_change_to_assignee_id?)
  39. if assignee.notifier.issue_assign && assignee.notifier.can_notify
  40. UserMailer.issue_assign_notification(self, assignee).deliver
  41. end
  42. ActivityFeed.create(
  43. user: assignee,
  44. kind: 'issue_assign_notification',
  45. project_owner: project.owner_uname,
  46. project_name: project.name,
  47. data: {
  48. user_name: assignee.name,
  49. user_email: assignee.email,
  50. issue_serial_id: serial_id,
  51. issue_title: title,
  52. project_id: project.id
  53. }
  54. )
  55. end
  56. # dont remove outdated issues link
  57. ::Comment.create_link_on_issues_from_item(self) if saved_change_to_title? ||
  58. saved_change_to_body?
  59. end
  60. 1 def send_hooks(action = :create)
  61. project.hooks.each{ |h| h.receive_issues(self, action) }
  62. end
  63. end

app/models/concerns/feed/user.rb

100.0% lines covered

7 relevant lines. 7 lines covered and 0 lines missed.
    
  1. 1 module Feed::User
  2. 1 extend ActiveSupport::Concern
  3. 1 included do
  4. 1 after_commit :new_user_notification, on: :create
  5. end
  6. 1 private
  7. 1 def new_user_notification
  8. 24 activity_feeds.create(
  9. kind: 'new_user_notification',
  10. data: { user_name: user_appeal, user_email: email }
  11. )
  12. end
  13. end

app/models/concerns/file_store_clean.rb

56.25% lines covered

16 relevant lines. 9 lines covered and 7 lines missed.
    
  1. 1 module FileStoreClean
  2. 1 extend ActiveSupport::Concern
  3. 1 included do
  4. 5 later :destroy, queue: :middle
  5. 5 later :later_destroy_files_from_file_store, queue: :middle
  6. end
  7. 1 def destroy
  8. destroy_files_from_file_store if Rails.env.production?
  9. super
  10. end
  11. 1 def sha1_of_file_store_files
  12. raise NotImplementedError, "You should implement this method"
  13. end
  14. 1 def destroy_files_from_file_store(args = sha1_of_file_store_files)
  15. files = *args
  16. files.each do |sha1|
  17. FileStoreService::File.new(sha1: sha1).destroy
  18. end
  19. end
  20. 1 def later_destroy_files_from_file_store(args)
  21. destroy_files_from_file_store(args)
  22. end
  23. end

app/models/concerns/flash_notify/finders.rb

76.92% lines covered

13 relevant lines. 10 lines covered and 3 lines missed.
    
  1. # Private: Finders of all sorts: methods to find FlashNotify records, methods to find
  2. # other records which belong to given FlashNotify.
  3. #
  4. # This module gets included into FlashNotify.
  5. 1 module FlashNotify::Finders
  6. 1 extend ActiveSupport::Concern
  7. 1 included do
  8. 1 scope :published, -> { where(published: true) }
  9. 1 after_commit :clear_caches
  10. 1 after_touch :clear_caches
  11. end
  12. 1 module ClassMethods
  13. # Public: Get cached first published FlashNotify record.
  14. #
  15. # Returns FlashNotify record or nil.
  16. 1 def published_first_cached
  17. Rails.cache.fetch('FlashNotify.published.first') do
  18. published.first
  19. end
  20. end
  21. end
  22. 1 protected
  23. # Private: after_commit and after_touch hook which clears find_cached cache.
  24. 1 def clear_caches
  25. Rails.cache.delete('FlashNotify.published.first')
  26. end
  27. end

app/models/concerns/git.rb

31.14% lines covered

167 relevant lines. 52 lines covered and 115 lines missed.
    
  1. 1 require 'nokogiri'
  2. 1 require 'open-uri'
  3. 1 module Git
  4. 1 extend ActiveSupport::Concern
  5. 1 included do
  6. 1 CONTENT_LIMIT = 100
  7. 1 has_attached_file :srpm
  8. 1 validates_attachment_size :srpm, less_than_or_equal_to: 500.megabytes
  9. 1 validates_attachment_content_type :srpm, content_type: ['application/octet-stream', "application/x-rpm", "application/x-redhat-package-manager"], message: I18n.t('layout.invalid_content_type')
  10. 1 after_create :create_git_repo
  11. 4 after_commit(on: :create) {|p| p.fork_git_repo unless p.is_root?} # later with resque
  12. 4 after_commit(on: :create) {|p| p.import_attached_srpm if p.srpm?} # later with resque # should be after create_git_repo
  13. 1 after_destroy :destroy_git_repo
  14. # after_rollback -> { destroy_git_repo rescue true if new_record? }
  15. 1 later :import_attached_srpm, queue: :fork_import
  16. 1 later :fork_git_repo, queue: :fork_import
  17. end
  18. 1 def repo
  19. begin
  20. 9 @repo ||= Grit::Repo.new(path)
  21. rescue => e
  22. 3 if !e.is_a?(Grit::NoSuchPathError) && !e.is_a?(Rugged::RepositoryError)
  23. Raven.capture_exception(e)
  24. end
  25. 3 Grit::Repo.new(GAP_REPO_PATH)
  26. end
  27. end
  28. 1 def path
  29. 21 build_path(name_with_owner)
  30. end
  31. 1 def versions
  32. repo.tags.map(&:name) + repo.branches.map(&:name)
  33. end
  34. 1 def find_blob_and_raw_of_spec_file(project_version)
  35. blob = repo.tree(project_version).contents.find{ |n| n.is_a?(Grit::Blob) && n.name =~ /.spec$/ }
  36. return unless blob
  37. raw = Grit::GitRuby::Repository.new(repo.path).get_raw_object_by_sha1(blob.id)
  38. [blob, raw]
  39. end
  40. 1 def create_branch(new_ref, from_ref, user)
  41. return false if new_ref.blank? || from_ref.blank? || !(from_commit = repo.commit(from_ref))
  42. status, out, err = repo.git.native(:branch, {process_info: true}, new_ref, from_commit.id)
  43. if status == 0
  44. Resque.enqueue(GitHook, owner.uname, name, from_commit.id, GitHook::ZERO, "refs/heads/#{new_ref}", 'commit', "user-#{user.id}", nil)
  45. return true
  46. end
  47. return false
  48. end
  49. 1 def delete_branch(branch, user)
  50. return false if default_branch == branch.name
  51. message = repo.git.native(:branch, {}, '-D', branch.name)
  52. if message.present?
  53. Resque.enqueue(GitHook, owner.uname, name, GitHook::ZERO, branch.commit.id, "refs/heads/#{branch.name}", 'commit', "user-#{user.id}", message)
  54. end
  55. return message.present?
  56. end
  57. 1 def update_file(path, data, options = {})
  58. head = options[:head].to_s || default_branch
  59. actor = get_actor(options[:actor])
  60. filename = File.split(path).last
  61. message = options[:message]
  62. message = "Updated file #{filename}" if message.nil? or message.empty?
  63. # can not write to unexisted branch
  64. return false if repo.branches.select{|b| b.name == head}.size != 1
  65. parent = repo.commits(head).first
  66. index = repo.index
  67. index.read_tree(parent.tree.id)
  68. # can not create new file
  69. return false if (index.current_tree / path).nil?
  70. system "sudo chown -R rosa:rosa #{repo.path}" #FIXME Permission denied - /mnt/gitstore/git_projects/...
  71. index.add(path, data)
  72. if sha1 = index.commit(message, parents: [parent], actor: actor, last_tree: parent.tree.id, head: head)
  73. Resque.enqueue(GitHook, owner.uname, name, sha1, sha1, "refs/heads/#{head}", 'commit', "user-#{options[:actor].id}", message)
  74. end
  75. sha1
  76. end
  77. 1 def paginate_commits(treeish, options = {})
  78. options[:page] = options[:page].try(:to_i) || 1
  79. options[:per_page] = options[:per_page].try(:to_i) || 20
  80. skip = options[:per_page] * (options[:page] - 1)
  81. last_page = (skip + options[:per_page]) >= repo.commit_count(treeish)
  82. [repo.commits(treeish, options[:per_page], skip), options[:page], last_page]
  83. end
  84. 1 def tree_info(tree, treeish = nil, path = nil, page = 0)
  85. return [] unless tree
  86. grouped = tree.contents.sort_by{|c| c.name.downcase}.group_by(&:class)
  87. contents = [
  88. grouped[Grit::Tree],
  89. grouped[Grit::Blob],
  90. grouped[Grit::Submodule]
  91. ].compact.flatten
  92. range = page*CONTENT_LIMIT..CONTENT_LIMIT+page*(CONTENT_LIMIT)-1
  93. contents[range].map do |node|
  94. node_path = File.join([path.present? ? path : nil, node.name].compact)
  95. [
  96. node,
  97. node_path,
  98. repo.log(treeish, node_path, max_count: 1).first
  99. ]
  100. end
  101. end
  102. 1 def import_srpm(srpm_path = srpm.path, branch_name = 'import')
  103. token = User.find_by(uname: 'rosa_system').authentication_token
  104. opts = [srpm_path, path, branch_name, Rails.root.join('bin', 'file-store.rb'), token, APP_CONFIG['file_store_url']].join(' ')
  105. system("#{Rails.root.join('bin', 'import_srpm.sh')} #{opts} >> /dev/null 2>&1")
  106. end
  107. 1 def is_empty?
  108. repo.branches.count == 0
  109. end
  110. 1 def total_commits_count
  111. return 0 if is_empty?
  112. %x(cd #{path} && git rev-list --all | wc -l).to_i
  113. end
  114. 1 protected
  115. 1 def aliases_path
  116. File.join(APP_CONFIG['git_path'], 'git_projects', '.aliases')
  117. end
  118. 1 def alias_path
  119. File.join(aliases_path, "#{alias_from_id}.git")
  120. end
  121. 1 def build_path(dir)
  122. 21 File.join(APP_CONFIG['git_path'], 'git_projects', "#{dir}.git")
  123. end
  124. 1 def import_attached_srpm
  125. if srpm?
  126. import_srpm # srpm.path
  127. self.srpm = nil; save # clear srpm
  128. end
  129. end
  130. 1 def create_git_repo
  131. 3 if is_root?
  132. 3 Grit::Repo.init_bare(path)
  133. 3 write_hook
  134. end
  135. end
  136. # Creates fork/alias for GIT repo
  137. 1 def fork_git_repo
  138. dummy = Grit::Repo.new(path) rescue nil
  139. # Do nothing if GIT repo already exist
  140. unless dummy
  141. if alias_from_id
  142. FileUtils.mkdir_p(aliases_path)
  143. if !Dir.exists?(alias_path) && alias_from
  144. # Move GIT repo into aliases
  145. FileUtils.mv(alias_from.path, alias_path, force: true)
  146. # Create link for GIT
  147. FileUtils.ln_sf alias_path, alias_from.path
  148. end
  149. # Create folder
  150. FileUtils.mkdir_p File.join(APP_CONFIG['git_path'], 'git_projects', owner_uname || owner.uname)
  151. # Create link for GIT
  152. FileUtils.ln_sf alias_path, path
  153. else
  154. parent.repo.fork_bare(path, shared: false)
  155. end
  156. end
  157. write_hook
  158. end
  159. 1 def destroy_git_repo
  160. FileUtils.rm_rf path
  161. return unless alias_from_id
  162. unless alias_from || Project.where.not(id: id).where(alias_from_id: alias_from_id).exists?
  163. FileUtils.rm_rf alias_path
  164. end
  165. end
  166. 1 def write_hook
  167. 3 hook = "/home/#{APP_CONFIG['shell_user']}/gitlab-shell/hooks/post-receive"
  168. 3 hook_file = File.join(path, 'hooks', 'post-receive')
  169. 3 FileUtils.ln_sf hook, hook_file
  170. end
  171. 1 def get_actor(actor = nil)
  172. @last_actor = case actor.class.to_s
  173. when 'Grit::Actor' then options[:actor]
  174. when 'Hash' then Grit::Actor.new(actor[:name], actor[:email])
  175. when 'String' then Grit::Actor.from_stirng(actor)
  176. else begin
  177. if actor.respond_to?(:name) and actor.respond_to?(:email)
  178. Grit::Actor.new(actor.name, actor.email)
  179. else
  180. config = Grit::Config.new(repo)
  181. Grit::Actor.new(config['user.name'], config['user.email'])
  182. end
  183. end
  184. end
  185. @last_actor
  186. end
  187. 1 module ClassMethods
  188. 1 MAX_SRC_SIZE = 1024*1024*256
  189. 1 def process_hook(owner_uname, repo, newrev, oldrev, ref, newrev_type, user = nil, message = nil)
  190. rec = GitHook.new(owner_uname, repo, newrev, oldrev, ref, newrev_type, user, message)
  191. Modules::Observers::ActivityFeed::Git.create_notifications rec
  192. end
  193. 1 def run_mass_import(url, srpms_list, visibility, owner, add_to_repository_id)
  194. doc = Nokogiri::HTML(open(url))
  195. links = doc.css("a[href$='.src.rpm']")
  196. return if links.count == 0
  197. filter = srpms_list.lines.map(&:chomp).map(&:strip).select(&:present?)
  198. repository = Repository.find add_to_repository_id
  199. platform = repository.platform
  200. dir = Dir.mktmpdir 'mass-import-', APP_CONFIG['tmpfs_path']
  201. links.each do |link|
  202. begin
  203. package = link.attributes['href'].value
  204. package.chomp!; package.strip!
  205. next if package.size == 0 || package !~ Project::NAME_REGEXP
  206. next if filter.present? && !filter.include?(package)
  207. uri = URI "#{url}/#{package}"
  208. srpm_file = "#{dir}/#{package}"
  209. Net::HTTP.start(uri.host) do |http|
  210. if http.request_head(uri.path)['content-length'].to_i < MAX_SRC_SIZE
  211. f = open(srpm_file, 'wb')
  212. http.request_get(uri.path) do |resp|
  213. resp.read_body{ |segment| f.write(segment) }
  214. end
  215. f.close
  216. end
  217. end
  218. if name = `rpm -q --qf '[%{Name}]' -p #{srpm_file}` and $?.success? and name.present?
  219. next if owner.projects.exists?(name: name)
  220. description = `rpm -q --qf '[%{Description}]' -p #{srpm_file}`.scrub('')
  221. project = owner.projects.build(
  222. name: name,
  223. description: description,
  224. visibility: visibility,
  225. is_package: false # See: Hook for #attach_to_personal_repository
  226. )
  227. project.owner = owner
  228. if project.save
  229. repository.projects << project rescue nil
  230. project.update(is_package: true)
  231. project.import_srpm srpm_file, platform.name
  232. end
  233. end
  234. rescue => e
  235. f.close if defined?(f)
  236. Raven.capture_exception(e, extra: {
  237. link: link.to_s,
  238. url: url,
  239. owner: owner
  240. })
  241. ensure
  242. File.delete srpm_file if srpm_file
  243. end
  244. end
  245. rescue => e
  246. Raven.capture_exception(e, extra: {
  247. url: url,
  248. owner: owner
  249. })
  250. ensure
  251. FileUtils.remove_entry_secure dir if dir
  252. end
  253. end
  254. end

app/models/concerns/owner.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. 1 module Owner
  2. 1 extend ActiveSupport::Concern
  3. 1 included do
  4. 2 validates :owner, presence: true
  5. 2 after_create do
  6. 21 relations.create(actor: owner, role: 'admin')
  7. end
  8. end
  9. end

app/models/concerns/personal_repository.rb

92.0% lines covered

25 relevant lines. 23 lines covered and 2 lines missed.
    
  1. 1 module PersonalRepository
  2. 1 extend ActiveSupport::Concern
  3. 1 included do
  4. 2 after_create :create_personal_repository, unless: :system?
  5. end
  6. 1 def create_personal_repository
  7. begin
  8. 12 pl = own_platforms.build
  9. 12 pl.owner = self
  10. 12 pl.name = "#{self.uname}_personal"
  11. 12 pl.default_branch = pl.name
  12. 12 pl.description = "#{self.uname}_personal"
  13. 12 pl.platform_type = Platform::TYPE_PERSONAL
  14. 12 pl.distrib_type = APP_CONFIG['distr_types'].first
  15. 12 pl.visibility = Platform::VISIBILITY_OPEN
  16. 12 pl.save!
  17. 12 rep = pl.repositories.build
  18. 12 rep.name = 'main'
  19. 12 rep.description = 'main'
  20. 12 rep.save!
  21. rescue Exception => e
  22. pl.now_destroy rescue false
  23. raise e
  24. end
  25. 12 return true
  26. end
  27. 1 def personal_platform
  28. 6 own_platforms.personal.first
  29. end
  30. 1 def personal_repository
  31. 3 personal_platform.repositories.first
  32. end
  33. end

app/models/concerns/platform/finders.rb

91.67% lines covered

24 relevant lines. 22 lines covered and 2 lines missed.
    
  1. # Private: Finders of all sorts: methods to find Platform records, methods to find
  2. # other records which belong to given Platform.
  3. #
  4. # This module gets included into Platform.
  5. 1 module Platform::Finders
  6. 1 extend ActiveSupport::Concern
  7. 1 included do
  8. 1 scope :search_order, -> { order(:name) }
  9. 1 scope :search_like, -> (q) { where("#{table_name}.name ILIKE ?", "%#{q.to_s.strip}%") }
  10. 1 scope :by_visibilities, -> (v) { where(visibility: v) }
  11. 1 scope :opened, -> { where(visibility: Platform::VISIBILITY_OPEN) }
  12. 1 scope :hidden, -> { where(visibility: Platform::VISIBILITY_HIDDEN) }
  13. 7 scope :by_type, -> (type) { where(platform_type: type) if type.present? }
  14. 1 scope :main, -> { by_type(Platform::TYPE_MAIN) }
  15. 7 scope :personal, -> { by_type(Platform::TYPE_PERSONAL) }
  16. 1 scope :waiting_for_regeneration, -> { where(status: Platform::WAITING_FOR_REGENERATION) }
  17. 1 after_commit :clear_caches
  18. 1 after_touch :clear_caches
  19. end
  20. 1 module ClassMethods
  21. # Public: Get cached Platform record by ID or name.
  22. #
  23. # platform_id - ID or Name (Numeric/String)
  24. #
  25. # Returns Platform record.
  26. # Raises ActiveRecord::RecordNotFound if nothing was found.
  27. 1 def find_cached(platform_id)
  28. Rails.cache.fetch(['Platform.find', platform_id]) do
  29. find(platform_id)
  30. end
  31. end
  32. end
  33. 1 protected
  34. # Private: after_commit and after_touch hook which clears find_cached cache.
  35. 1 def clear_caches
  36. 18 Rails.cache.delete(['Platform.find', id])
  37. 18 Rails.cache.delete(['Platform.find', name])
  38. 18 if chg = previous_changes["name"]
  39. 6 Rails.cache.delete(['Platform.find', chg.first])
  40. end
  41. end
  42. end

app/models/concerns/product_build_lists/abf_workerable.rb

51.85% lines covered

27 relevant lines. 14 lines covered and 13 lines missed.
    
  1. # Internal: various definitions and instance methods related to AbfWorker.
  2. #
  3. # This module gets mixed in into ProductBuildList class.
  4. 1 module ProductBuildLists::AbfWorkerable
  5. 1 extend ActiveSupport::Concern
  6. 1 CACHED_CHROOT_TOKEN_DESCRIPTION = 'cached-chroot'
  7. 1 include AbfWorkerMethods
  8. 1 included do
  9. 1 delegate :url_helpers, to: 'Rails.application.routes'
  10. 1 after_create :add_job_to_abf_worker_queue
  11. end
  12. ######################################
  13. # Instance methods #
  14. ######################################
  15. 1 def sha1_of_file_store_files
  16. (results || []).map{ |r| r['sha1'] }.compact
  17. end
  18. 1 protected
  19. 1 def abf_worker_priority
  20. ''
  21. end
  22. 1 def abf_worker_base_queue
  23. 'iso_worker'
  24. end
  25. 1 def abf_worker_args
  26. {
  27. id: id,
  28. srcpath: abf_worker_srcpath,
  29. params: abf_worker_params,
  30. time_living: time_living,
  31. main_script: main_script,
  32. platform: {
  33. type: product.platform.distrib_type,
  34. name: product.platform.name,
  35. arch: arch.name
  36. },
  37. user: {uname: user.try(:uname), email: user.try(:email)}
  38. }
  39. end
  40. # Private: Get URL to project archive.
  41. #
  42. # Returns the String.
  43. 1 def abf_worker_srcpath
  44. file_name = "#{project.name}-#{commit_hash}"
  45. opts = default_url_options
  46. opts.merge!({user: user.authentication_token, password: ''}) if user.present?
  47. url_helpers.archive_url(
  48. project.name_with_owner,
  49. file_name,
  50. 'tar.gz',
  51. opts
  52. )
  53. end
  54. # Private: Get params for ABF worker task.
  55. #
  56. # Returns the String with space separated params.
  57. 1 def abf_worker_params
  58. p = {
  59. 'BUILD_ID' => id,
  60. 'PROJECT' => project.name_with_owner,
  61. 'PROJECT_VERSION' => project_version,
  62. 'COMMIT_HASH' => commit_hash,
  63. }
  64. if product.platform.hidden?
  65. token = product.platform.tokens.by_active.where(description: CACHED_CHROOT_TOKEN_DESCRIPTION).first
  66. p.merge!('TOKEN' => token.authentication_token) if token
  67. end
  68. p.map{ |k, v| "#{k}=#{v}" } * ' ' + ' ' + params.to_s
  69. end
  70. end

app/models/concerns/product_build_lists/statusable.rb

86.36% lines covered

44 relevant lines. 38 lines covered and 6 lines missed.
    
  1. # Internal: various definitions and instance methods related to status.
  2. #
  3. # This module gets mixed in into ProductBuildList class.
  4. 1 module ProductBuildLists::Statusable
  5. 1 extend ActiveSupport::Concern
  6. 1 BUILD_COMPLETED = 0
  7. 1 BUILD_FAILED = 1
  8. 1 BUILD_PENDING = 2
  9. 1 BUILD_STARTED = 3
  10. 1 BUILD_CANCELED = 4
  11. 1 BUILD_CANCELING = 5
  12. 1 BUILD_COMPLETED_PARTIALLY = 6
  13. STATUSES = [
  14. 1 BUILD_STARTED,
  15. BUILD_COMPLETED,
  16. BUILD_COMPLETED_PARTIALLY,
  17. BUILD_FAILED,
  18. BUILD_PENDING,
  19. BUILD_CANCELED,
  20. BUILD_CANCELING
  21. ].freeze
  22. HUMAN_STATUSES = {
  23. 1 BUILD_STARTED => :build_started,
  24. BUILD_COMPLETED => :build_completed,
  25. BUILD_COMPLETED_PARTIALLY => :build_completed_partially,
  26. BUILD_FAILED => :build_failed,
  27. BUILD_PENDING => :build_pending,
  28. BUILD_CANCELED => :build_canceled,
  29. BUILD_CANCELING => :build_canceling
  30. }.freeze
  31. 1 included do
  32. 1 scope :for_status, -> (status) { where(status: status) if status.present? }
  33. 1 validates :status,
  34. presence: true,
  35. inclusion: { in: STATUSES }
  36. 1 before_destroy :can_destroy?
  37. 1 state_machine :status, initial: :build_pending do
  38. 1 event :start_build do
  39. 1 transition build_pending: :build_started
  40. end
  41. 1 event :cancel do
  42. 1 transition [:build_pending, :build_started] => :build_canceling
  43. end
  44. 1 after_transition on: :cancel, do: :cancel_job
  45. # build_canceling: :build_canceled - canceling from UI
  46. # build_started: :build_canceled - canceling from worker by time-out (time_living has been expired)
  47. 1 event :build_canceled do
  48. 1 transition [:build_canceling, :build_started] => :build_canceled
  49. end
  50. # build_canceling: :build_completed - Worker hasn't time to cancel building because build had been already completed
  51. 1 event :build_success do
  52. 1 transition [:build_started, :build_canceling] => :build_completed
  53. end
  54. # build_canceling: :build_completed - Worker hasn't time to cancel building because build had been already completed
  55. 1 event :build_success_partially do
  56. 1 transition [:build_started, :build_canceling] => :build_completed_partially
  57. end
  58. # build_canceling: :build_failed - Worker hasn't time to cancel building because build had been already failed
  59. 1 event :build_error do
  60. 1 transition [:build_started, :build_canceling] => :build_failed
  61. end
  62. 1 HUMAN_STATUSES.each do |code,name|
  63. 7 state name, value: code
  64. end
  65. end
  66. end
  67. 1 module ClassMethods
  68. 1 def human_status(status)
  69. I18n.t("layout.product_build_lists.statuses.#{HUMAN_STATUSES[status]}")
  70. end
  71. end
  72. ######################################
  73. # Instance methods #
  74. ######################################
  75. 1 def build_started?
  76. status == BUILD_STARTED
  77. end
  78. 1 def build_canceling?
  79. status == BUILD_CANCELING
  80. end
  81. 1 def can_destroy?
  82. [BUILD_STARTED, BUILD_PENDING, BUILD_CANCELING].exclude?(status)
  83. end
  84. 1 def can_cancel?
  85. [BUILD_STARTED, BUILD_PENDING].include?(status)
  86. end
  87. 1 def human_status
  88. self.class.human_status(status)
  89. end
  90. end

app/models/concerns/project/default_branch.rb

43.33% lines covered

30 relevant lines. 13 lines covered and 17 lines missed.
    
  1. # Internal: various definitions and instance methods related to default_branch.
  2. #
  3. # This module gets mixed in into Project class.
  4. 1 module Project::DefaultBranch
  5. 1 extend ActiveSupport::Concern
  6. 1 include DefaultBranchable
  7. 1 included do
  8. 1 validate :check_default_branch
  9. 1 after_update :set_new_git_head
  10. end
  11. ######################################
  12. # Instance methods #
  13. ######################################
  14. # Public: Get default branch according to owner configs.
  15. #
  16. # Returns found String branch name.
  17. 1 def resolve_default_branch
  18. return default_branch unless owner.is_a?(Group) && owner.default_branch.present?
  19. return default_branch unless repo.branches.map(&:name).include?(owner.default_branch)
  20. return owner.default_branch unless default_branch.present?
  21. default_branch == 'master' ? owner.default_branch : default_branch
  22. end
  23. # Public: Finds branch name for platforms.
  24. #
  25. # save_to_platform - The save Platform.
  26. # build_for_platform - The build Platform.
  27. #
  28. # Returns found String branch name.
  29. 1 def project_version_for(save_to_platform, build_for_platform)
  30. if repo.commits("#{save_to_platform.default_branch}").try(:first).try(:id)
  31. save_to_platform.default_branch
  32. elsif repo.commits("#{build_for_platform.default_branch}").try(:first).try(:id)
  33. build_for_platform.default_branch
  34. else
  35. resolve_default_branch
  36. end
  37. end
  38. # Public: Finds default head.
  39. #
  40. # treeish - The String treeish.
  41. #
  42. # Returns found String head.
  43. 1 def default_head(treeish = nil) # maybe need change 'head'?
  44. # Attention!
  45. # repo.commit(nil) => <Grit::Commit "b6c0f81deb17590d22fc07ba0bbd4aa700256f61">
  46. # repo.commit(nil.to_s) => nil
  47. return treeish if treeish.present? && repo.commit(treeish).present?
  48. if repo.branches_and_tags.map(&:name).include?(treeish || resolve_default_branch)
  49. treeish || resolve_default_branch
  50. else
  51. repo.branches_and_tags[0].try(:name) || resolve_default_branch
  52. end
  53. end
  54. 1 protected
  55. # Private: Set git head.
  56. 1 def set_new_git_head
  57. if saved_change_to_default_branch? && repo.branches.map(&:name).include?(default_branch)
  58. repo.git.send(:'symbolic-ref', {}, 'HEAD', "refs/heads/#{default_branch}")
  59. Project.project_aliases(self).update_all default_branch: default_branch
  60. end
  61. end
  62. # Private: Validation for checking that the default branch is exist.
  63. 1 def check_default_branch
  64. 3 if self.repo.branches.count > 0 && self.repo.branches.map(&:name).exclude?(self.default_branch)
  65. errors.add :default_branch, I18n.t('activerecord.errors.project.default_branch')
  66. end
  67. end
  68. end

app/models/concerns/project/finders.rb

80.0% lines covered

35 relevant lines. 28 lines covered and 7 lines missed.
    
  1. # Private: Finders of all sorts: methods to find Project records, methods to find
  2. # other records which belong to given Project.
  3. #
  4. # This module gets included into Project.
  5. 1 module Project::Finders
  6. 1 extend ActiveSupport::Concern
  7. 1 included do
  8. 1 scope :recent, -> { order(:name) }
  9. 1 scope :search_order, -> { order('CHAR_LENGTH(projects.name) ASC') }
  10. 1 scope :search_like, ->(q) {
  11. q = q.to_s.strip
  12. by_name("%#{q}%").search_order if q.present?
  13. }
  14. 7 scope :by_name, ->(name) { where('projects.name ILIKE ?', name) if name.present? }
  15. 1 scope :by_owner, ->(name) { where('projects.owner_uname ILIKE ?', "%#{name}%") if name.present? }
  16. 1 scope :by_owner_and_name, ->(*params) {
  17. term = params.map(&:strip).join('/').downcase
  18. where("lower(concat(owner_uname, '/', name)) ILIKE ?", "%#{term}%") if term.present?
  19. }
  20. 1 scope :by_visibilities, ->(v) { where(visibility: v) }
  21. 1 scope :opened, -> { where(visibility: 'open') }
  22. 1 scope :package, -> { where(is_package: true) }
  23. 1 scope :addable_to_repository, ->(repository_id) {
  24. where('projects.id NOT IN (
  25. SELECT ptr.project_id
  26. FROM project_to_repositories AS ptr
  27. WHERE ptr.repository_id = ?)', repository_id)
  28. }
  29. 1 scope :by_owners, ->(group_owner_ids, user_owner_ids) {
  30. where("(projects.owner_id in (?) AND projects.owner_type = 'Group') OR
  31. (projects.owner_id in (?) AND projects.owner_type = 'User')", group_owner_ids, user_owner_ids)
  32. }
  33. 1 scope :project_aliases, ->(project) {
  34. where.not(id: project.id).
  35. where('alias_from_id IN (:ids) OR id IN (:ids)', { ids: [project.alias_from_id, project.id].compact })
  36. }
  37. 1 after_commit :clear_caches
  38. 1 after_touch :clear_caches
  39. end
  40. 1 module ClassMethods
  41. # Public: Get cached Project record by owner and name.
  42. #
  43. # Returns Project record.
  44. # Raises ActiveRecord::RecordNotFound if nothing was found.
  45. 1 def find_by_owner_and_name(first, last = nil)
  46. 1 arr = first.try(:split, '/') || []
  47. 1 arr = (arr << last).compact
  48. 1 return nil if arr.length != 2
  49. 1 find_by(owner_uname: arr.first, name: arr.last) || by_owner_and_name(*arr).first
  50. # Rails.cache.fetch(['Project.find_by_owner_and_name', arr.first, arr.last]) do
  51. # end || by_owner_and_name(*arr).first
  52. end
  53. 1 def find_by_owner_and_name!(first, last = nil)
  54. 1 find_by_owner_and_name(first, last) or raise ActiveRecord::RecordNotFound
  55. end
  56. end
  57. 1 protected
  58. # Private: after_commit and after_touch hook which clears find_cached cache.
  59. 1 def clear_caches
  60. 3 Rails.cache.delete(['Project.find_by_owner_and_name', owner_uname, name])
  61. end
  62. end

app/models/concerns/regeneration_status.rb

71.43% lines covered

21 relevant lines. 15 lines covered and 6 lines missed.
    
  1. 1 module RegenerationStatus
  2. 1 extend ActiveSupport::Concern
  3. 1 READY = 0
  4. 1 WAITING_FOR_REGENERATION = 100
  5. 1 REGENERATING = 200
  6. HUMAN_STATUSES = {
  7. 1 READY => :ready,
  8. WAITING_FOR_REGENERATION => :waiting_for_regeneration,
  9. REGENERATING => :regenerating
  10. }
  11. HUMAN_REGENERATION_STATUSES = {
  12. 1 AbfWorker::BaseObserver::COMPLETED => :completed,
  13. AbfWorker::BaseObserver::FAILED => :failed,
  14. AbfWorker::BaseObserver::CANCELED => :canceled
  15. }.freeze
  16. 1 included do
  17. 2 after_update :cleanup_file_store
  18. 2 def sha1_of_file_store_files
  19. files = []
  20. files << last_regenerated_log_sha1 if last_regenerated_log_sha1.present?
  21. files
  22. end
  23. 2 def human_regeneration_status
  24. self.class::HUMAN_REGENERATION_STATUSES[last_regenerated_status] || :no_data
  25. end
  26. 2 def human_status
  27. self.class::HUMAN_STATUSES[status] || :no_data
  28. end
  29. 2 def cleanup_file_store
  30. 12 old_log_sha1 = last_regenerated_log_sha1_was
  31. 12 if old_log_sha1.present? && old_log_sha1 != last_regenerated_log_sha1
  32. later_destroy_files_from_file_store([old_log_sha1])
  33. end
  34. end
  35. end
  36. end

app/models/concerns/time_living.rb

57.14% lines covered

14 relevant lines. 8 lines covered and 6 lines missed.
    
  1. 1 module TimeLiving
  2. 1 extend ActiveSupport::Concern
  3. 1 included do
  4. 3 validates :time_living, numericality: { only_integer: true }, presence: true
  5. 3 validate -> {
  6. # MIN_TIME_LIVING <= time_living <= MAX_TIME_LIVING or
  7. # 2 min <= time_living <= 12 hours
  8. # time_living in seconds
  9. min = self.class.const_defined?(:MIN_TIME_LIVING) ? self.class::MIN_TIME_LIVING : 120
  10. max = self.class.const_defined?(:MAX_TIME_LIVING) ? self.class::MAX_TIME_LIVING : 43200
  11. if min > time_living.to_i || time_living.to_i > max
  12. errors.add :time_living,
  13. I18n.t('flash.time_living.numericality_error', min: (min / 60), max: (max / 60))
  14. end
  15. }
  16. 3 before_validation :convert_time_living
  17. end
  18. 1 protected
  19. 1 def convert_time_living
  20. self.time_living = time_living.to_i * 60 if time_living_was.to_i != time_living.to_i
  21. end
  22. end

app/models/concerns/token_authenticatable.rb

76.47% lines covered

17 relevant lines. 13 lines covered and 4 lines missed.
    
  1. 1 module TokenAuthenticatable
  2. 1 extend ActiveSupport::Concern
  3. 1 module ClassMethods
  4. 1 def find_by_authentication_token(authentication_token = nil)
  5. if authentication_token
  6. where(authentication_token: authentication_token).first
  7. end
  8. end
  9. end
  10. 1 def ensure_authentication_token
  11. 12 if authentication_token.blank?
  12. 12 self.authentication_token = generate_authentication_token
  13. end
  14. end
  15. 1 def reset_authentication_token!
  16. self.authentication_token = generate_authentication_token
  17. save
  18. end
  19. 1 private
  20. 1 def generate_authentication_token
  21. 12 loop do
  22. 12 token = Devise.friendly_token
  23. 12 break token unless self.class.unscoped.where(authentication_token: token).first
  24. end
  25. end
  26. end

app/models/concerns/url_helper.rb

40.0% lines covered

5 relevant lines. 2 lines covered and 3 lines missed.
    
  1. 1 module UrlHelper
  2. 1 def default_url_options
  3. host ||= EventLog.current_controller.request.host_with_port rescue ::Rosa::Application.config.action_mailer.default_url_options[:host]
  4. protocol ||= APP_CONFIG['mailer_https_url'] ? 'https' : 'http' rescue 'http'
  5. { host: host, protocol: protocol }
  6. end
  7. end

app/models/concerns/web_hooks.rb

100.0% lines covered

30 relevant lines. 30 lines covered and 0 lines missed.
    
  1. 1 module WebHooks
  2. 1 class << self
  3. 1 protected
  4. 1 def add_hook(name)
  5. 3 NAMES << name.to_s
  6. 3 @schema = []
  7. 3 yield if block_given?
  8. 3 SCHEMA[name] = @schema
  9. 3 @schema = []
  10. end
  11. 1 def add_to_schema(type, attrs)
  12. 5 attrs.each do |attr|
  13. 13 @schema << [type, attr.to_sym]
  14. end
  15. end
  16. 1 def boolean(*attrs)
  17. 1 add_to_schema :boolean, attrs
  18. end
  19. 1 def string(*attrs)
  20. 3 add_to_schema :string, attrs
  21. end
  22. 1 def password(*attrs)
  23. 1 add_to_schema :password, attrs
  24. end
  25. end
  26. 1 NAMES = []
  27. 1 SCHEMA = {}
  28. 1 add_hook :web do
  29. 1 string :url
  30. end
  31. # temporarily disabled
  32. # add_hook :hipchat do
  33. # string :auth_token, :room, :restrict_to_branch
  34. # boolean :notify
  35. # end
  36. 1 add_hook :irc do
  37. 1 string :server, :port, :room, :nick, :branch_regexes
  38. 1 password :password
  39. 1 boolean :ssl, :message_without_join, :no_colors, :long_url, :notice
  40. end
  41. 1 add_hook :jabber do
  42. 1 string :user
  43. end
  44. 1 SCHEMA.freeze
  45. 1 NAMES.freeze
  46. end

app/models/concerns/wiki.rb

64.71% lines covered

17 relevant lines. 11 lines covered and 6 lines missed.
    
  1. 1 module Wiki
  2. 1 extend ActiveSupport::Concern
  3. 1 included do
  4. 1 after_save :create_wiki
  5. 1 after_destroy :destroy_wiki
  6. end
  7. 1 def wiki_path
  8. build_path(wiki_repo_name)
  9. end
  10. 1 def wiki_repo_name
  11. File.join owner.uname, "#{name}.wiki"
  12. end
  13. 1 protected
  14. 1 def create_wiki
  15. 3 if has_wiki && !FileTest.exist?(wiki_path)
  16. Grit::Repo.init_bare(wiki_path)
  17. wiki = Gollum::Wiki.new(wiki_path, { base_path: Rails.application.routes.url_helpers.project_wiki_index_path(self) })
  18. wiki.write_page('Home', :markdown, I18n.t("wiki.seed.welcome_content"),
  19. { name: owner.name, email: owner.email, message: 'Initial commit' })
  20. end
  21. end
  22. 1 def destroy_wiki
  23. FileUtils.rm_rf wiki_path
  24. end
  25. end

app/models/event_log.rb

55.0% lines covered

20 relevant lines. 11 lines covered and 9 lines missed.
    
  1. 1 class EventLog < ActiveRecord::Base
  2. 1 belongs_to :user
  3. 1 belongs_to :eventable, polymorphic: true
  4. # self.per_page = 1
  5. 1 scope :eager_loading, -> { preload(:user) }
  6. 1 scope :default_order, -> { order(id: :desc) }
  7. 1 before_create do
  8. self.user_name = user.try(:uname) || 'guest'
  9. self.eventable_name ||= eventable.name if eventable.respond_to?(:name)
  10. end
  11. # after_create { self.class.current_controller = nil }
  12. 1 class << self
  13. 1 def create_with_current_controller(attributes)
  14. create(attributes) do |el|
  15. el.user = current_controller.current_user
  16. el.ip = current_controller.request.remote_ip
  17. el.controller = current_controller.class.to_s
  18. el.action = current_controller.action_name
  19. el.protocol = 'web'
  20. end
  21. end
  22. 1 def current_controller
  23. Thread.current[:current_controller]
  24. end
  25. 1 def current_controller=(ctrl)
  26. 3 Thread.current[:current_controller] = ctrl
  27. end
  28. end
  29. end

app/models/flash_notify.rb

75.0% lines covered

12 relevant lines. 9 lines covered and 3 lines missed.
    
  1. 1 require 'digest/md5'
  2. 1 class FlashNotify < ActiveRecord::Base
  3. 1 include FlashNotify::Finders
  4. 1 STATUSES = %w[error success info]
  5. 1 validates :status, inclusion: {in: STATUSES}
  6. 1 validates :body_ru, :body_en, :status, presence: true
  7. 1 def hash_id
  8. @digest ||= Digest::MD5.hexdigest("#{self.id}-#{self.updated_at}")
  9. end
  10. 1 def body(language)
  11. read_attribute("body_#{language}")
  12. end
  13. 1 def should_show?(cookie_hash_id)
  14. cookie_hash_id != hash_id && published
  15. end
  16. end

app/models/git_hook.rb

28.26% lines covered

46 relevant lines. 13 lines covered and 33 lines missed.
    
  1. 1 class GitHook
  2. 1 include Feed::Git
  3. 1 include Resque::Plugins::Status
  4. 1 ZERO = '0000000000000000000000000000000000000000'
  5. 1 @queue = :hook
  6. 1 attr_reader :repo, :newrev, :oldrev, :newrev_type, :oldrev_type, :refname,
  7. :change_type, :rev, :rev_type, :refname_type, :owner, :project, :user, :message
  8. 1 def self.perform(*options)
  9. self.process(*options)
  10. end
  11. 1 def initialize(owner_uname, repo, newrev, oldrev, ref, newrev_type, user = nil, message = nil)
  12. @repo, @newrev, @oldrev, @refname, @newrev_type, @user, @message = repo, newrev, oldrev, ref, newrev_type, user, message
  13. if @owner = User.where(uname: owner_uname).first || Group.where(uname: owner_uname).first!
  14. @project = @owner.own_projects.where(name: repo).first!
  15. end
  16. @change_type, @user = git_change_type, find_user(user)
  17. git_revision_types
  18. commit_type
  19. end
  20. 1 def git_change_type
  21. if oldrev == ZERO
  22. return 'create'
  23. elsif newrev == ZERO
  24. return 'delete'
  25. else
  26. return 'update'
  27. end
  28. end
  29. 1 def git_revision_types
  30. case change_type
  31. when 'create', 'update'
  32. @rev = newrev
  33. when 'delete'
  34. @rev = oldrev
  35. end
  36. @rev_type = newrev_type
  37. end
  38. 1 def commit_type
  39. if refname =~ /refs\/tags\/*/ && rev_type == 'commit'
  40. # un-annotated tag
  41. @refname_type= 'tag'
  42. #~ short_refname=refname + '##refs/tags/'
  43. elsif refname =~ /refs\/tags\/*/ && rev_type == 'tag'
  44. # annotated tag
  45. @refname_type="annotated tag"
  46. #~ short_refname= refname + '##refs/tags/'
  47. elsif refname =~ /refs\/heads\/*/ && rev_type == 'commit'
  48. # branch
  49. @refname_type= 'branch'
  50. elsif refname =~ /refs\/remotes\/*'/ && rev_type == 'commit'
  51. # tracking branch
  52. @refname_type="tracking branch"
  53. @short_refname= refname + '##refs/remotes/'
  54. else
  55. # Anything else (is there anything else?)
  56. @refname_type= "*** Unknown type of update to $refname (#{rev_type})"
  57. end
  58. end
  59. 1 def self.process(*args)
  60. Feed::Git.create_notifications(args.size > 1 ? GitHook.new(*args) : args.first)
  61. end
  62. 1 def find_user(user)
  63. if user.blank?
  64. # Local push
  65. User.find_by(email: project.repo.commit(newrev).author.email) rescue nil
  66. elsif user =~ /\Auser-\d+\Z/
  67. # git push over http
  68. User.find(user.gsub('user-', ''))
  69. elsif user =~ /\Akey-\d+\Z/
  70. # git push over ssh
  71. SshKey.find(user.gsub('key-', '')).try(:user)
  72. end
  73. end
  74. end

app/models/group.rb

77.5% lines covered

40 relevant lines. 31 lines covered and 9 lines missed.
    
  1. 1 class Group < Avatar
  2. 1 include ActsLikeMember
  3. 1 include PersonalRepository
  4. 1 include DefaultBranchable
  5. 1 belongs_to :owner, class_name: 'User'
  6. 1 has_many :relations, as: :actor, dependent: :destroy
  7. 1 has_many :actors, as: :target, class_name: 'Relation', dependent: :destroy
  8. 1 has_many :targets, as: :actor, class_name: 'Relation', dependent: :destroy
  9. 1 has_many :members, through: :actors, source: :actor, source_type: 'User', autosave: true
  10. 1 has_many :projects, through: :targets, source: :target, source_type: 'Project', autosave: true
  11. 1 has_many :own_projects, as: :owner, class_name: 'Project', dependent: :destroy
  12. 1 has_many :own_platforms, as: :owner, class_name: 'Platform', dependent: :destroy
  13. 1 validates :owner, presence: true
  14. 1 validates :uname, presence: true,
  15. uniqueness: {case_sensitive: false},
  16. format: {with: /\A[a-z0-9_]+\z/},
  17. reserved_name: true,
  18. length: { maximum: 100 }
  19. 1 validate { errors.add(:uname, :taken) if User.by_uname(uname).present? }
  20. 1 scope :opened, -> { all }
  21. 1 scope :by_owner, ->(owner) { where(owner_id: owner.id) }
  22. 1 scope :by_admin, ->(admin) {
  23. joins(:actors).where('relations.role' => 'admin', 'relations.actor_id' => admin.id, 'relations.actor_type' => 'User')
  24. }
  25. 1 scope :by_admin_and_writer, ->(actor) {
  26. joins(:actors).where('relations.role' => ['admin', 'writer'], 'relations.actor_id' => actor.id, 'relations.actor_type' => 'User')
  27. }
  28. 1 attr_readonly :uname
  29. 1 attr_accessor :delete_avatar
  30. 1 delegate :email, :user_appeal, to: :owner
  31. 1 after_create :add_owner_to_members
  32. 1 def self.can_own_project(user)
  33. (by_owner(user) | by_admin_and_writer(user))
  34. end
  35. 1 def name
  36. uname
  37. end
  38. 1 def add_member(member, role = 'admin')
  39. Relation.add_member(member, self, role, :actors)
  40. end
  41. 1 def remove_member(member)
  42. Relation.remove_member(member, self)
  43. end
  44. 1 def system?
  45. false
  46. end
  47. 1 def fullname
  48. return description.present? ? "#{uname} (#{description})" : uname
  49. end
  50. 1 protected
  51. 1 def add_owner_to_members
  52. Relation.create_with_role(self.owner, self, 'admin') # members << self.owner if !members.exists?(id: self.owner.id)
  53. end
  54. end

app/models/hook.rb

28.79% lines covered

66 relevant lines. 19 lines covered and 47 lines missed.
    
  1. 1 class Hook < ActiveRecord::Base
  2. 1 include WebHooks
  3. 1 include UrlHelper
  4. 1 include Rails.application.routes.url_helpers
  5. 1 belongs_to :project
  6. 1 before_validation :cleanup_data
  7. 1 validates :project, :data, presence: true
  8. 1 validates :name, presence: true, inclusion: {in: NAMES}
  9. 1 serialize :data, Hash
  10. 1 scope :for_name, ->(name) { where(name: name) if name.present? }
  11. 1 def receive_issues(issue, action)
  12. pull = issue.pull_request
  13. return if action.to_sym == :create && pull
  14. default_url_options
  15. payload = meta(issue.project, issue.user)
  16. base_params = {
  17. number: issue.serial_id,
  18. state: issue.status,
  19. title: issue.title,
  20. body: issue.body,
  21. user: {login: issue.user.uname},
  22. }
  23. if pull
  24. total_commits = pull.repo.commits_between(pull.to_commit, pull.from_commit).count
  25. repo_owner = pull.to_project.owner.uname
  26. post 'pull_request', {
  27. payload: payload.merge(
  28. action: (pull.ready? ? 'opened' : pull.status),
  29. pull_request: base_params.merge(
  30. commits: total_commits,
  31. head: {label: "#{pull.from_project.owner.uname}:#{pull.from_ref}"},
  32. base: {label: "#{repo_owner}:#{pull.to_ref}"},
  33. html_url: project_pull_request_url(pull.to_project, pull)
  34. )
  35. ).to_json
  36. }
  37. else
  38. post 'issues', {
  39. payload: payload.merge(
  40. action: (issue.closed? ? 'closed' : 'opened'),
  41. issue: base_params.merge(
  42. html_url: project_issue_url(issue.project, issue)
  43. )
  44. ).to_json
  45. }
  46. end
  47. end
  48. 1 later :receive_issues, queue: :notification
  49. 1 def receive_push(git_hook)
  50. default_url_options
  51. project = Project.find(git_hook['project']['id'])
  52. user = User.find(git_hook['user']['id'])
  53. payload = meta(project, user)
  54. oldrev, newrev, change_type = git_hook.values_at *%w(oldrev newrev change_type)
  55. commits = []
  56. payload.merge!(before: oldrev, after: newrev)
  57. if %w(delete create).exclude? change_type
  58. payload.merge!(
  59. :compare => diff_url(project, "#{oldrev[0..6]}...#{newrev[0..6]}")
  60. )
  61. if oldrev == newrev
  62. commits = [project.repo.commit(newrev)]
  63. modified = commits.first.stats.files.map{|f| f[0]}
  64. else
  65. commits = project.repo.commits_between(oldrev, newrev)
  66. end
  67. end
  68. post 'push', {
  69. payload: payload.merge(
  70. ref: git_hook['refname'],
  71. commits: commits.map{ |commit|
  72. files = changed_files commit
  73. {
  74. id: commit.id,
  75. message: commit.message,
  76. distinct: true,
  77. url: commit_url(project, commit),
  78. removed: files[:removed],
  79. added: files[:added],
  80. modified: files[:modified],
  81. timestamp: commit.committed_date,
  82. author: {name: commit.committer.name, email: commit.committer.email}
  83. }
  84. }
  85. ).to_json
  86. }
  87. end
  88. 1 later :receive_push, queue: :notification
  89. 1 protected
  90. 1 def post(action, params)
  91. github_services = APP_CONFIG['github_services']
  92. uri = URI "http://#{github_services['ip']}:#{github_services['port']}/#{name}/#{action}"
  93. Net::HTTP.post_form uri, params.merge(data: data.to_json)
  94. rescue # Dont care about it
  95. end
  96. 1 def meta(project, user)
  97. {
  98. repository: {
  99. name: project.name,
  100. url: project_url(project),
  101. owner: { login: project.owner.uname }
  102. },
  103. sender: {login: user.uname},
  104. pusher: {name: user.uname}
  105. }
  106. end
  107. 1 def cleanup_data
  108. if self.name.present? && fields = SCHEMA[self.name.to_sym]
  109. new_data = {}
  110. fields.each { |type, field| new_data[field] = self.data[field] }
  111. self.data = new_data
  112. end
  113. end
  114. 1 def changed_files(commit)
  115. removed, added, modified = [], [], []
  116. commit.show.each do |diff|
  117. if diff.renamed_file
  118. added << diff.b_path
  119. removed << diff.a_path
  120. elsif diff.new_file
  121. added << diff.b_path
  122. elsif diff.deleted_file
  123. removed << diff.a_path
  124. else
  125. modified << diff.a_path
  126. end
  127. end
  128. { removed: removed, added: added, modified: modified }
  129. end
  130. end

app/models/invite.rb

66.67% lines covered

24 relevant lines. 16 lines covered and 8 lines missed.
    
  1. 1 class Invite < ActiveRecord::Base
  2. 1 TTL = 3.days
  3. 1 MAX_UNUSED_INVITES = 5
  4. 1 belongs_to :user
  5. 1 belongs_to :invited_user, class_name: 'User'
  6. 1 before_create :generate_invite_key
  7. 1 scope :owned, ->(u) { where(user_id: u.try(:id) || u) }
  8. 1 scope :unused, ->() { where(invited_user_id: nil) }
  9. 1 scope :outdated, ->() { where('created_at <= ? AND invited_user_id IS NULL', TTL.ago) }
  10. 1 validate :max_count_exceeded
  11. 1 def used?
  12. !invited_user.nil?
  13. end
  14. 1 def unused?
  15. invited_user.nil?
  16. end
  17. 1 def remaining_ttl
  18. ret = TTL - (Time.now.utc - created_at)
  19. return 0 if ret < 0
  20. ret
  21. end
  22. 1 private
  23. 1 def generate_invite_key
  24. self.invite_key = SecureRandom.hex(20)
  25. end
  26. 1 def max_count_exceeded
  27. if !persisted? && user_id.present? && Invite.owned(user_id).unused.count >= 5
  28. errors.add(
  29. :base,
  30. I18n.t('flash.invite.max_limit_exceeded', number: MAX_UNUSED_INVITES)
  31. )
  32. end
  33. end
  34. end

app/models/issue.rb

54.88% lines covered

82 relevant lines. 45 lines covered and 37 lines missed.
    
  1. 1 class Issue < ActiveRecord::Base
  2. 1 include Feed::Issue
  3. STATUSES = [
  4. 1 STATUS_OPEN = 'open',
  5. STATUS_REOPEN = 'reopen',
  6. STATUS_CLOSED = 'closed'
  7. ]
  8. 1 HASH_TAG_REGEXP = /([a-zA-Z0-9\-_]*\/)?([a-zA-Z0-9\-_]*)?#([0-9]+)/
  9. 1 self.per_page = 20
  10. 1 belongs_to :project
  11. 1 belongs_to :user
  12. 1 belongs_to :assignee,
  13. class_name: 'User',
  14. foreign_key: 'assignee_id',
  15. optional: true
  16. 1 belongs_to :closer,
  17. class_name: 'User',
  18. foreign_key: 'closed_by',
  19. optional: true
  20. 1 has_many :comments,
  21. as: :commentable,
  22. dependent: :destroy
  23. 1 has_many :subscribes,
  24. as: :subscribeable,
  25. dependent: :destroy
  26. 1 has_many :labelings,
  27. dependent: :destroy
  28. 1 has_many :labels,
  29. -> { distinct },
  30. through: :labelings
  31. 1 has_one :pull_request#, dependent: :destroy
  32. 1 validates :title, :body, :project, presence: true
  33. 1 validates :title, length: { maximum: 100 }
  34. 1 validates :body, length: { maximum: 10000 }
  35. 1 after_create :set_serial_id
  36. 1 after_create :subscribe_users
  37. 1 after_update :subscribe_issue_assigned_user
  38. 1 before_create :update_statistic
  39. 1 before_update :update_statistic
  40. 1 accepts_nested_attributes_for :labelings,
  41. reject_if: -> (attributes) { attributes['label_id'].blank? },
  42. allow_destroy: true
  43. 1 scope :opened, -> { where(status: [STATUS_OPEN, STATUS_REOPEN]) }
  44. 1 scope :closed, -> { where(status: STATUS_CLOSED) }
  45. 3 scope :needed_checking, -> { where(issues: { status: %w(open reopen blocked ready already) }) }
  46. 3 scope :not_closed_or_merged, -> { needed_checking }
  47. 1 scope :closed_or_merged, -> { where(issues: { status: %w(closed merged) }) }
  48. # Using mb_chars for correct transform to lowercase ('Русский Текст'.downcase => "Русский Текст")
  49. 1 scope :search_like, ->(q) {
  50. where("#{table_name}.title ILIKE ?", "%#{q.mb_chars.downcase}%") if q.present?
  51. }
  52. 1 scope :without_pull_requests, -> {
  53. 1 where('NOT EXISTS (select null from pull_requests as pr where pr.issue_id = issues.id)').
  54. references(:pull_requests)
  55. }
  56. 1 attr_accessor :new_pull_request
  57. 1 def assign_uname
  58. assignee.uname if assignee
  59. end
  60. 1 def to_param
  61. serial_id.to_s
  62. end
  63. 1 def subscribe_creator(creator_id)
  64. unless self.subscribes.exists?(user_id: creator_id)
  65. self.subscribes.create(user_id: creator_id)
  66. end
  67. end
  68. 1 def closed?
  69. closed_by && closed_at && status == STATUS_CLOSED
  70. end
  71. 1 def set_close(closed_by)
  72. self.closed_at = Time.now.utc
  73. self.closer = closed_by
  74. self.status = STATUS_CLOSED
  75. end
  76. 1 def set_open
  77. self.closed_at = self.closed_by = nil
  78. self.status = STATUS_REOPEN
  79. end
  80. 1 def collect_recipients
  81. recipients = self.project.all_members
  82. recipients = recipients | [self.assignee] if self.assignee
  83. recipients
  84. end
  85. 1 def self.find_by_hash_tag(hash_tag, current_user, project)
  86. hash_tag =~ HASH_TAG_REGEXP
  87. owner_uname = Regexp.last_match[1].presence || Regexp.last_match[2].presence || project.owner.uname
  88. project_name = Regexp.last_match[1] ? Regexp.last_match[2] : project.name
  89. serial_id = Regexp.last_match[3]
  90. project = Project.find_by_owner_and_name(owner_uname.chomp('/'), project_name)
  91. return nil unless project
  92. return nil unless ProjectPolicy.new(current_user, project).show?
  93. project.issues.where(serial_id: serial_id).first
  94. end
  95. 1 protected
  96. 1 def update_statistic
  97. key = (pull_request || new_pull_request) ? Statistic::KEY_PULL_REQUEST : Statistic::KEY_ISSUE
  98. Statistic.statsd_increment(
  99. activity_at: Time.now,
  100. key: "#{key}.#{status}",
  101. project_id: project_id,
  102. user_id: closed_by || user_id,
  103. ) if new_record? || status_changed?
  104. end
  105. 1 def set_serial_id
  106. self.serial_id = self.project.issues.maximum(:serial_id).to_i+1
  107. self.save!
  108. end
  109. 1 def subscribe_users
  110. collect_recipients.each do |recipient|
  111. if recipient.notifier.new_comment && !self.subscribes.exists?(user_id: recipient.id)
  112. ss = self.subscribes.create(user_id: recipient.id)
  113. end
  114. end
  115. end
  116. 1 def subscribe_issue_assigned_user
  117. if self.assignee_id && saved_change_to_attribute?(:assignee_id)
  118. was_assignee_id = saved_change_to_attribute(:assignee_id)
  119. self.subscribes.where(user_id: was_assignee_id).first.try(:destroy) unless was_assignee_id.blank?
  120. if self.assignee.notifier.issue_assign && !self.subscribes.exists?(user_id: self.assignee_id)
  121. self.subscribes.create(user_id: self.assignee_id)
  122. end
  123. end
  124. end
  125. end

app/models/key_pair.rb

32.65% lines covered

49 relevant lines. 16 lines covered and 33 lines missed.
    
  1. 1 require 'open3'
  2. 1 class KeyPair < ActiveRecord::Base
  3. 1 belongs_to :repository
  4. 1 belongs_to :user
  5. 1 attr_accessor :fingerprint
  6. 1 attr_encrypted :secret, key: APP_CONFIG['keys']['key_pair_secret_key']
  7. 1 validates :repository, :user, presence: true
  8. 1 validates :secret, :public, presence: true, length: { maximum: 10000 }, on: :create
  9. 1 validates :repository_id, uniqueness: { message: I18n.t("activerecord.errors.key_pair.repo_key_exists") }
  10. 1 validate :check_keys
  11. 1 before_create { |record| record.key_id = @fingerprint }
  12. 1 after_create { |record| record.repository.resign }
  13. 1 protected
  14. 1 def check_keys
  15. dir = Dir.mktmpdir 'keys-', APP_CONFIG['tmpfs_path']
  16. begin
  17. %w(pubring secring).each do |kind|
  18. filename = "#{dir}/#{kind}"
  19. open("#{filename}.txt", "w") { |f| f.write self.send(kind == 'pubring' ? :public : :secret) }
  20. system "gpg --homedir #{dir} --dearmor < #{filename}.txt > #{filename}.gpg"
  21. end
  22. public_key = get_info_of_key "#{dir}/pubring.txt"
  23. secret_key = get_info_of_key "#{dir}/secring.txt"
  24. if correct_key?(public_key, :public) & correct_key?(secret_key, :secret)
  25. if public_key[:fingerprint] != secret_key[:fingerprint]
  26. errors.add :secret, I18n.t('activerecord.errors.key_pair.wrong_keys')
  27. else
  28. stdin, stdout, stderr = Open3.popen3("echo '\n\n\n\n\nsave' | LC_ALL=en gpg --command-fd 0 --homedir #{dir} --edit-key #{secret_key[:keyid]} passwd")
  29. output = stderr.read
  30. if output =~ /Invalid\spassphrase/
  31. errors.add :secret, I18n.t('activerecord.errors.key_pair.key_has_passphrase')
  32. else
  33. @fingerprint = secret_key[:fingerprint]
  34. end
  35. end
  36. end
  37. ensure
  38. # remove the directory.
  39. FileUtils.remove_entry_secure dir
  40. end
  41. end
  42. 1 def correct_key?(info, field)
  43. if info.empty? || info[:type].blank? || info[:fingerprint].blank? || info[:keyid].blank?
  44. errors.add field, I18n.t('activerecord.errors.key_pair.wrong_key')
  45. return false
  46. else
  47. if info[:type] != field
  48. errors.add field, I18n.t("activerecord.errors.key_pair.wrong_#{field}_key")
  49. return false
  50. end
  51. end
  52. return true
  53. end
  54. 1 def get_info_of_key(file_path)
  55. results = {}
  56. str = %x[ cat #{file_path} | gpg --quiet --import-options import-show --dry-run --keyid-format LONG --import | sed -n 1,2p ]
  57. info = str.strip.split("\n")
  58. if info.size == 2
  59. results[:fingerprint] = info[1].gsub(/.*\=/, '').strip.gsub(/\s/, ':')
  60. results[:type] = info[0] =~ /^pub\s/ ? :public : nil
  61. results[:type] ||= info[0] =~ /^sec#\s/ ? :secret : nil
  62. if keyid = info[0].match(/\/[\w]+\s/)
  63. results[:keyid] = keyid[0].strip[1..-1]
  64. end
  65. end
  66. return results
  67. end
  68. end

app/models/label.rb

100.0% lines covered

8 relevant lines. 8 lines covered and 0 lines missed.
    
  1. 1 class Label < ActiveRecord::Base
  2. 1 has_many :labelings, dependent: :destroy
  3. 1 has_many :issues, through: :labelings
  4. 1 belongs_to :project
  5. 1 validates :name, uniqueness: { scope: :project_id }
  6. 1 validates :name, length: { in: 1..20 }
  7. 1 validates :color, presence: true
  8. 1 validates :color, format: { with: /\A([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})\z/, message: I18n.t('layout.issues.invalid_labels') }
  9. end

app/models/labeling.rb

100.0% lines covered

3 relevant lines. 3 lines covered and 0 lines missed.
    
  1. 1 class Labeling < ActiveRecord::Base
  2. 1 belongs_to :issue
  3. 1 belongs_to :label
  4. end

app/models/mass_build.rb

55.56% lines covered

99 relevant lines. 55 lines covered and 44 lines missed.
    
  1. 1 class MassBuild < ActiveRecord::Base
  2. 1 include ExternalNodable
  3. 1 AUTO_PUBLISH_STATUSES = %w(none default testing)
  4. 1 STATUSES, HUMAN_STATUSES = [], {}
  5. [
  6. 1 %w(SUCCESS 0),
  7. %w(BUILD_STARTED 3000),
  8. %w(BUILD_PENDING 2000),
  9. ].each do |kind, value|
  10. 3 value = value.to_i
  11. 3 const_set kind, value
  12. 3 STATUSES << value
  13. 3 HUMAN_STATUSES[value] = kind.downcase.to_sym
  14. end
  15. 1 STATUSES.freeze
  16. 1 HUMAN_STATUSES.freeze
  17. 1 state_machine :status, initial: :build_pending do
  18. 1 event :start do
  19. 1 transition build_pending: :build_started
  20. end
  21. 1 event :done do
  22. 1 transition build_started: :success
  23. end
  24. 1 HUMAN_STATUSES.each do |code,name|
  25. 3 state name, value: code
  26. end
  27. end
  28. 1 belongs_to :build_for_platform, -> { where(platform_type: 'main') }, class_name: 'Platform'
  29. 1 belongs_to :save_to_platform, class_name: 'Platform'
  30. 1 belongs_to :user
  31. 1 has_many :build_lists, dependent: :destroy
  32. 1 serialize :extra_repositories, Array
  33. 1 serialize :extra_build_lists, Array
  34. 1 serialize :extra_mass_builds, Array
  35. 1 scope :recent, -> { order(created_at: :desc) }
  36. 1 scope :outdated, -> { where("#{table_name}.created_at < ?", Time.now + 1.day - BuildList::MAX_LIVE_TIME) }
  37. 1 scope :search_like, -> (q) { where("#{table_name}.description ILIKE ?", "%#{q}%") if q.present? }
  38. 1 attr_accessor :arches, :repositories
  39. 1 validates :save_to_platform_id,
  40. :build_for_platform_id,
  41. :arch_names,
  42. :name,
  43. :user_id,
  44. presence: true
  45. 1 validates :projects_list,
  46. presence: true,
  47. length: { maximum: 500_000 }
  48. 1 validates :description,
  49. length: { maximum: 255 }
  50. 1 validates :auto_publish_status,
  51. inclusion: { in: AUTO_PUBLISH_STATUSES }
  52. 1 validates :increase_release_tag,
  53. :use_cached_chroot,
  54. :use_extra_tests,
  55. inclusion: { in: [true, false] }
  56. 1 after_commit :build_all, on: :create, if: Proc.new { |mb| mb.extra_mass_builds.blank? }
  57. 1 before_validation :set_data, on: :create
  58. 1 COUNT_STATUSES = %i(
  59. build_lists
  60. build_published
  61. build_pending
  62. build_started
  63. build_publish
  64. build_error
  65. success
  66. build_canceled
  67. )
  68. 1 def build_all
  69. return unless start
  70. # later with resque
  71. arches_list = arch_names ? Arch.where(name: arch_names.split(', ')) : Arch.all
  72. projects_list.lines.each do |name|
  73. next if name.blank?
  74. name.chomp!; name.strip!
  75. if project = Project.joins(:repositories).where('repositories.id in (?)', save_to_platform.repository_ids).find_by(name: name)
  76. begin
  77. return if self.reload.stop_build
  78. # Ensures that user has rights to create a build_list
  79. next unless ProjectPolicy.new(user, project).write?
  80. increase_rt = increase_release_tag?
  81. arches_list.each do |arch|
  82. rep_id = (project.repository_ids & save_to_platform.repository_ids).first
  83. project.build_for(self, rep_id, arch, 0, increase_rt)
  84. increase_rt = false
  85. end
  86. rescue RuntimeError, Exception
  87. end
  88. else
  89. MassBuild.increment_counter :missed_projects_count, id
  90. list = (missed_projects_list || '') << "#{name}\n"
  91. update_column :missed_projects_list, list
  92. end
  93. end
  94. done
  95. end
  96. 1 later :build_all, queue: :low
  97. 1 def generate_failed_builds_list
  98. generate_list BuildList::BUILD_ERROR
  99. end
  100. 1 def generate_tests_failed_builds_list
  101. generate_list BuildList::TESTS_FAILED
  102. end
  103. 1 def generate_success_builds_list
  104. generate_list BuildList::SUCCESS
  105. end
  106. 1 def cancel_all
  107. update_column(:stop_build, true)
  108. build_lists.find_each(batch_size: 100) do |bl|
  109. bl.cancel
  110. end
  111. end
  112. 1 later :cancel_all, queue: :low
  113. 1 def publish_success_builds(user)
  114. publish user, BuildList::SUCCESS, BuildList::FAILED_PUBLISH
  115. end
  116. 1 later :publish_success_builds, queue: :low
  117. 1 def publish_test_failed_builds(user)
  118. publish user, BuildList::TESTS_FAILED
  119. end
  120. 1 later :publish_test_failed_builds, queue: :low
  121. 1 COUNT_STATUSES.each do |stat|
  122. 8 stat_count = "#{stat}_count"
  123. define_method stat_count do
  124. Rails.cache.fetch([self, "cached_#{stat_count}"], expires_in: 5.minutes) do
  125. build_lists.where(status: BuildList::HUMAN_STATUSES.key(stat)).count
  126. end
  127. 8 end if stat != :build_lists
  128. end
  129. 1 private
  130. 1 def generate_list(status)
  131. report = ""
  132. BuildList.select('build_lists.id, projects.name as project_name, arches.name as arch_name').
  133. where(
  134. status: status,
  135. mass_build_id: self.id
  136. ).joins(:project, :arch).find_each(batch_size: 100) do |build_list|
  137. report << "ID: #{build_list.id}; "
  138. report << "PROJECT_NAME: #{build_list.project_name}; "
  139. report << "ARCH: #{build_list.arch_name}\n"
  140. end
  141. report
  142. end
  143. 1 def publish(user, *statuses)
  144. builds = build_lists.where(status: statuses)
  145. builds.update_all(publisher_id: user.id)
  146. builds.find_each(batch_size: 50) do |bl|
  147. bl.now_publish if bl.can_publish? && bl.has_new_packages?
  148. end
  149. end
  150. 1 def set_data
  151. if save_to_platform
  152. self.name = "#{Time.now.utc.to_date.strftime("%d.%b")}-#{save_to_platform.name}"
  153. self.build_for_platform = save_to_platform if save_to_platform.main?
  154. end
  155. self.arch_names = Arch.where(id: arches).map(&:name).join(", ")
  156. self.projects_list = projects_list.lines.map do |name|
  157. name.chomp.strip if name.present?
  158. end.compact.uniq.join("\r\n") if projects_list.present?
  159. end
  160. end

app/models/platform.rb

59.3% lines covered

172 relevant lines. 102 lines covered and 70 lines missed.
    
  1. 1 class Platform < ActiveRecord::Base
  2. 1 extend FriendlyId
  3. 1 friendly_id :name, use: [:finders]
  4. 1 include FileStoreClean
  5. 1 include RegenerationStatus
  6. 1 include Owner
  7. 1 include EventLoggable
  8. 1 include EmptyMetadata
  9. 1 include DefaultBranchable
  10. 1 include Platform::Finders
  11. 1 self.per_page = 20
  12. 1 CACHED_CHROOT_PRODUCT_NAME = 'cached-chroot'
  13. 1 AUTOMATIC_METADATA_REGENERATIONS = %w(day week)
  14. VISIBILITIES = [
  15. 1 VISIBILITY_OPEN = 'open',
  16. VISIBILITY_HIDDEN = 'hidden'
  17. ]
  18. 1 NAME_PATTERN = /[\w\-\.]+/
  19. 1 HUMAN_STATUSES = HUMAN_STATUSES.clone.freeze
  20. TYPES = [
  21. 1 TYPE_PERSONAL = 'personal',
  22. TYPE_MAIN = 'main'
  23. ]
  24. 1 belongs_to :parent, class_name: 'Platform', foreign_key: 'parent_platform_id', optional: true
  25. 1 belongs_to :owner, polymorphic: true
  26. 1 has_many :repositories, dependent: :destroy
  27. 1 has_many :key_pairs, through: :repositories
  28. 1 has_many :projects, through: :repositories
  29. 1 has_many :products, dependent: :destroy
  30. 1 has_many :tokens, as: :subject, dependent: :destroy
  31. 1 has_many :platform_arch_settings, dependent: :destroy
  32. 1 has_many :repository_statuses
  33. 1 has_many :relations, as: :target, dependent: :destroy
  34. 1 has_many :actors, as: :target, class_name: 'Relation', dependent: :destroy
  35. 1 has_many :members, through: :actors, source: :actor, source_type: 'User'
  36. 1 has_and_belongs_to_many :advisories
  37. 1 has_many :packages, class_name: "BuildList::Package", dependent: :destroy
  38. 1 has_many :mass_builds, foreign_key: :save_to_platform_id
  39. 1 validates :description,
  40. presence: true,
  41. length: { maximum: 10000 }
  42. 1 validates :visibility,
  43. presence: true,
  44. inclusion: { in: VISIBILITIES }
  45. 1 validates :platform_type,
  46. presence: true,
  47. inclusion: { in: TYPES }
  48. 1 validates :automatic_metadata_regeneration,
  49. inclusion: { in: AUTOMATIC_METADATA_REGENERATIONS },
  50. allow_blank: true
  51. 1 validates :name,
  52. uniqueness: { case_sensitive: false },
  53. presence: true,
  54. format: { with: /\A#{NAME_PATTERN}\z/ },
  55. length: { maximum: 100 }
  56. 1 validates :default_branch,
  57. presence: true
  58. 1 validates :distrib_type,
  59. presence: true,
  60. inclusion: { in: APP_CONFIG['distr_types'] }
  61. 1 validate -> {
  62. 30 if released_was && !released
  63. errors.add(:released, I18n.t('flash.platform.released_status_can_not_be_changed'))
  64. end
  65. }
  66. 1 validate -> {
  67. 12 if personal? && (owner_id_changed? || owner_type_changed?)
  68. errors.add :owner, I18n.t('flash.platform.owner_can_not_be_changed')
  69. end
  70. }, on: :update
  71. 1 before_create :create_directory
  72. 1 before_destroy :detele_directory
  73. 1 after_update :freeze_platform_and_update_repos
  74. 1 after_update :update_owner_relation
  75. 19 after_commit -> { symlink_directory unless hidden? }, on: :create
  76. 1 after_destroy -> { remove_symlink_directory unless hidden? }
  77. 1 accepts_nested_attributes_for :platform_arch_settings, allow_destroy: true
  78. 1 attr_accessor :admin_id, :term
  79. 1 attr_readonly :name, :distrib_type, :parent_platform_id, :platform_type
  80. 1 state_machine :status, initial: :ready do
  81. 1 after_transition on: :ready, do: :notify_users
  82. 1 event :ready do
  83. 1 transition regenerating: :ready
  84. end
  85. 1 event :regenerate do
  86. 1 transition ready: :waiting_for_regeneration, if: ->(p) { p.main? }
  87. end
  88. 1 event :start_regeneration do
  89. 1 transition waiting_for_regeneration: :regenerating
  90. end
  91. 1 HUMAN_STATUSES.each do |code,name|
  92. 3 state name, value: code
  93. end
  94. end
  95. 1 def clear
  96. system("rm -Rf #{ APP_CONFIG['root_path'] }/platforms/#{ self.name }/repository/*")
  97. end
  98. 1 def urpmi_list(host = nil, pair = nil, add_commands = true, repository_name = 'main')
  99. host ||= default_host
  100. urpmi_commands = ActiveSupport::OrderedHash.new
  101. # TODO: rename method or create separate methods for mdv and rhel
  102. # Platform.main.opened.where(distrib_type: APP_CONFIG['distr_types'].first).each do |pl|
  103. arches = Arch.all.to_a
  104. Platform.main.opened.each do |pl|
  105. urpmi_commands[pl.name] = {}
  106. # FIXME should support restricting access to the hidden platform
  107. arches.each do |arch|
  108. tail = "/#{arch.name}/#{repository_name}/release"
  109. command = add_commands ? "urpmi.addmedia #{name} " : ''
  110. command << "#{APP_CONFIG['downloads_url']}/#{name}/repository/#{pl.name}#{tail}"
  111. urpmi_commands[pl.name][arch.name] = command
  112. end
  113. end
  114. return urpmi_commands
  115. end
  116. 1 def path
  117. build_path(name)
  118. end
  119. 1 def add_member(member, role = 'admin')
  120. Relation.add_member(member, self, role)
  121. end
  122. 1 def remove_member(member)
  123. Relation.remove_member(member, self)
  124. end
  125. 1 def symlink_path
  126. Rails.root.join("public", "downloads", name)
  127. end
  128. # Returns URL to repository, for example:
  129. # - http://abf-downloads.rosalinux.ru/rosa-server2012/repository/x86_64/base/
  130. # - http://abf-downloads.rosalinux.ru/uname_personal/repository/rosa-server2012/x86_64/base/
  131. 1 def public_downloads_url(subplatform_name = nil, arch = nil, repo = nil)
  132. "#{APP_CONFIG['downloads_url']}/#{name}/repository/".tap do |url|
  133. url << "#{subplatform_name}/" if subplatform_name.present?
  134. url << "#{arch}/" if arch.present?
  135. url << "#{repo}/" if repo.present?
  136. end
  137. end
  138. 1 def hidden?
  139. 20 visibility == VISIBILITY_HIDDEN
  140. end
  141. 1 def personal?
  142. 12 platform_type == TYPE_PERSONAL
  143. end
  144. 1 def main?
  145. 15 platform_type == TYPE_MAIN
  146. end
  147. 1 def base_clone(attrs = {}) # :description, :name, :owner
  148. dup.tap do |c|
  149. attrs.each {|k,v| c.send("#{k}=", v)} # c.attributes = attrs
  150. c.updated_at = nil; c.created_at = nil
  151. c.parent = self; c.released = false
  152. end
  153. end
  154. 1 def clone_relations(from = parent)
  155. self.repositories = from.repositories.map{|r| r.full_clone(platform_id: id)}
  156. self.products = from.products.map(&:full_clone)
  157. end
  158. 1 def full_clone(attrs = {})
  159. base_clone(attrs).tap do |c|
  160. with_skip {c.save} and c.clone_relations(self) and c.fs_clone # later with resque
  161. end
  162. end
  163. 1 def change_visibility
  164. if hidden?
  165. update(visibility: VISIBILITY_OPEN)
  166. else
  167. update(visibility: VISIBILITY_HIDDEN)
  168. end
  169. end
  170. 1 def symlink_directory
  171. # umount_directory_for_rsync # TODO ignore errors
  172. system("ln -s #{path} #{symlink_path}")
  173. Arch.all.each do |arch|
  174. str = "country=Russian Federation,city=Moscow,latitude=52.18,longitude=48.88,bw=1GB,version=2011,arch=#{arch.name},type=distrib,url=#{public_downloads_url}\n"
  175. File.open(File.join(symlink_path, "#{name}.#{arch.name}.list"), 'w') {|f| f.write(str) }
  176. end
  177. end
  178. 1 later :symlink_directory, queue: :middle
  179. 1 def remove_symlink_directory
  180. system("rm -Rf #{symlink_path}")
  181. end
  182. 1 def update_owner_relation
  183. 12 if owner_id_was != owner_id
  184. r = relations.where(actor_id: owner_id_was, actor_type: owner_type_was).first
  185. r.update(actor_id: owner_id, actor_type: owner_type)
  186. end
  187. end
  188. 1 def destroy
  189. with_skip {super} # avoid cascade XML RPC requests
  190. end
  191. 1 later :destroy, queue: :low
  192. 1 def default_host
  193. EventLog.current_controller.request.host_with_port rescue ::Rosa::Application.config.action_mailer.default_url_options[:host]
  194. end
  195. # Checks access rights to platform and caching for 1 day.
  196. 1 def self.allowed?(path, token)
  197. platform_name = path.gsub(/^[\/]+/, '')
  198. .match(/^(#{NAME_PATTERN}\/|#{NAME_PATTERN}$)/)
  199. return true unless platform_name
  200. platform_name = platform_name[0].gsub(/\//, '')
  201. Rails.cache.fetch([platform_name, token, :platform_allowed], expires_in: 2.minutes) do
  202. platform = Platform.find_by name: platform_name
  203. next false unless platform
  204. next true unless platform.hidden?
  205. return false if token.blank?
  206. return true if platform.tokens.by_active.where(authentication_token: token).exists?
  207. user = User.find_by(authentication_token: token)
  208. !!(user && PlatformPolicy.new(user, platform).show?)
  209. end
  210. end
  211. 1 def cached_chroot(arch)
  212. return false if personal?
  213. Rails.cache.fetch([:cached_chroot, name, arch], expires_in: 10.minutes) do
  214. product = products.where(name: CACHED_CHROOT_PRODUCT_NAME).first
  215. next false unless product
  216. pbl = product.product_build_lists.for_status(ProductBuildList::BUILD_COMPLETED).recent.first
  217. next false unless pbl
  218. result = pbl.results.find{ |r| r['file_name'] =~ /-#{arch}.tar.gz$/ }
  219. result.present? ? result['sha1'] : false
  220. end
  221. end
  222. 1 def self.autostart_metadata_regeneration(value)
  223. Platform.main.where(automatic_metadata_regeneration: value).each(&:regenerate)
  224. end
  225. 1 def self.availables_main_platforms(user)
  226. p_ids = Rails.cache.fetch([:availables_main_platforms, user], expires_in: 10.minutes) do
  227. PlatformPolicy::Scope.new(user, Platform).show.main.joins(:repositories).
  228. where('repositories.id IS NOT NULL').uniq.pluck(:id)
  229. end
  230. Platform.preload(:repositories).where(id: p_ids).order(:name)
  231. end
  232. 1 protected
  233. 1 def create_directory
  234. 18 system("mkdir -p -m 0777 #{build_path([name, 'repository'])}")
  235. end
  236. 1 def build_path(dir)
  237. 18 File.join(APP_CONFIG['root_path'], 'platforms', dir)
  238. end
  239. 1 def detele_directory
  240. FileUtils.rm_rf path
  241. end
  242. 1 def fs_clone(old_name = parent.name, new_name = name)
  243. FileUtils.cp_r "#{parent.path}/repository", path
  244. end
  245. 1 later :fs_clone, queue: :low
  246. 1 def freeze_platform_and_update_repos
  247. 12 if released_changed? && released == true
  248. repositories.update_all(publish_without_qa: false)
  249. end
  250. end
  251. 1 def notify_users
  252. users = members.includes(:notifier).select{ |u| u.notifier.can_notify? }
  253. users.each{ |u| UserMailer.metadata_regeneration_notification(self, u).deliver }
  254. end
  255. end

app/models/platform_arch_setting.rb

92.31% lines covered

13 relevant lines. 12 lines covered and 1 lines missed.
    
  1. 1 class PlatformArchSetting < ActiveRecord::Base
  2. 1 DEFAULT_TIME_LIVING = 43200 # seconds, 12 hours
  3. 1 MIN_TIME_LIVING = 600 # seconds, 10 minutes
  4. 1 MAX_TIME_LIVING = 360000 # seconds, 100 hours, 4 day and 4 hours
  5. 1 include TimeLiving
  6. 1 belongs_to :arch
  7. 1 belongs_to :platform
  8. 1 validates :arch, :platform, presence: true
  9. 1 validates :platform_id, uniqueness: { scope: :arch_id }
  10. 1 validate lambda {
  11. errors.add(:platform, I18n.t('flash.platform_arch_settings.wrong_platform')) unless platform.main?
  12. }
  13. 1 scope :by_arch, ->(arch) { where(arch_id: arch) if arch.present? }
  14. 1 scope :by_default, -> { where(default: true) }
  15. end

app/models/platform_content.rb

27.27% lines covered

44 relevant lines. 12 lines covered and 32 lines missed.
    
  1. 1 class PlatformContent
  2. 1 attr_reader :path
  3. 1 def initialize(platform, path)
  4. @platform, @path = platform, path
  5. end
  6. 1 def build_list
  7. return @build_list if !!@build_list
  8. return nil if @path !~ /\/(release|updates)+\/[\w\-\.\+]+$/
  9. return nil unless repository_name = @path.match(/\/[\w]+\/(release|updates)\//)
  10. repository_name = repository_name[0].gsub(/\/(release|updates)\/$/, '').gsub('/', '')
  11. repository = @platform.repositories.where(name: repository_name).first
  12. return nil unless repository
  13. if @platform.main?
  14. build_for_platform = @platform
  15. else
  16. bfp_name = @path.match(/\/#{@platform.name}\/repository\/[\w]+\//)
  17. return nil unless bfp_name
  18. bfp_name = bfp_name[0].gsub(/\/#{@platform.name}\/repository\//, '').gsub('/', '')
  19. build_for_platform = Platform.main.find_by name: bfp_name
  20. return nil unless build_for_platform
  21. end
  22. @build_list = BuildList.for_status(BuildList::BUILD_PUBLISHED)
  23. .for_platform(build_for_platform)
  24. .scoped_to_save_platform(@platform)
  25. .where(save_to_repository_id: repository)
  26. .where(build_list_packages: {fullname: name, actual: true})
  27. .joins(:packages)
  28. .last
  29. return @build_list
  30. end
  31. 1 def name
  32. @name ||= @path.gsub(/.*#{File::SEPARATOR}/, '')
  33. end
  34. 1 def size
  35. @size ||= File.size(@path) rescue nil
  36. end
  37. 1 def is_folder?
  38. @is_folder.nil? ? (@is_folder = File.directory?(@path)) : @is_folder
  39. end
  40. 1 def download_url
  41. "#{APP_CONFIG['downloads_url']}/#{@platform.name}#{subpath}"
  42. end
  43. 1 def subpath
  44. @subpath ||= @path.gsub(/^#{@platform.path}/, '')
  45. end
  46. 1 def self.find_by_platform(platform, path, term)
  47. # Strip out the non-ascii character
  48. term = (term || '').strip.gsub(/[\\\/]+/, '')
  49. .gsub(/[^\w\-\+\.]/, '_')
  50. path = sanitize_path(path)
  51. results = Dir.glob(File.join(platform.path, path, "*#{term}*"))
  52. if term
  53. results = results.sort_by(&:length)
  54. else
  55. results = results.sort
  56. end
  57. results.map{ |p| PlatformContent.new(platform, p) }
  58. end
  59. 1 def self.remove_file(platform, path)
  60. path = File.join(platform.path, sanitize_path(path))
  61. FileUtils.rm_f(path) if File.exist?(path)
  62. end
  63. 1 def self.sanitize_path(path)
  64. path.split(File::SEPARATOR).map(&:strip).select(&:present?)
  65. .map{ |p|
  66. # Strip out the non-ascii character
  67. p.gsub(/[\\\/]+/, '')
  68. .gsub(/^[\.]+/, '')
  69. .gsub(/[^\w\-\+\.]/, '_')
  70. }.join(File::SEPARATOR)
  71. end
  72. end

app/models/product.rb

50.0% lines covered

34 relevant lines. 17 lines covered and 17 lines missed.
    
  1. 1 class Product < ActiveRecord::Base
  2. 1 include TimeLiving
  3. 1 include Autostart
  4. 1 include EventLoggable
  5. 1 belongs_to :platform
  6. 1 belongs_to :project
  7. 1 has_many :product_build_lists, dependent: :destroy
  8. 1 validates :name, presence: true,
  9. uniqueness: { scope: :platform_id },
  10. length: { maximum: 100 }
  11. 1 validates :project, presence: true
  12. 1 validates :main_script, :params, length: { maximum: 255 }
  13. 1 scope :recent, -> { order(:name) }
  14. 1 attr_readonly :platform_id
  15. 1 def full_clone(attrs = {})
  16. dup.tap do |c|
  17. attrs.each {|k,v| c.send("#{k}=", v)}
  18. c.time_living = c.time_living.to_i / 60 # see: TimeLiving#convert_time_living
  19. c.platform_id = nil
  20. c.product_build_lists = []
  21. c.updated_at = nil; c.created_at = nil
  22. end
  23. end
  24. 1 class << self
  25. 1 Autostart::HUMAN_AUTOSTART_STATUSES.each do |autostart_status, human_autostart_status|
  26. 3 define_method "autostart_iso_builds_#{human_autostart_status}" do
  27. autostart_iso_builds autostart_status
  28. end
  29. end
  30. end
  31. 1 def self.autostart_iso_builds(autostart_status)
  32. Product.where(autostart_status: autostart_status).each do |product|
  33. pbl = product.product_build_lists.new
  34. [:params, :main_script, :project, :project_version].each do |k|
  35. pbl.send "#{k}=", product.send(k)
  36. end
  37. owner = product.platform.owner
  38. pbl.user = owner.is_a?(User) ? owner : owner.owner
  39. pbl.autostarted = true
  40. pbl.base_url = "http://#{product.platform.default_host}"
  41. pbl.time_living = product.time_living / 60
  42. pbl.save
  43. end
  44. end
  45. end

app/models/product_build_list.rb

88.24% lines covered

34 relevant lines. 30 lines covered and 4 lines missed.
    
  1. 1 class ProductBuildList < ActiveRecord::Base
  2. 1 include CommitAndVersion
  3. 1 include TimeLiving
  4. 1 include FileStoreClean
  5. 1 include UrlHelper
  6. 1 include EventLoggable
  7. 1 include ProductBuildLists::Statusable
  8. 1 include ProductBuildLists::AbfWorkerable
  9. 1 LIVE_TIME = 2.week # for autostart
  10. 1 MAX_LIVE_TIME = 3.month # for manual start;
  11. 1 belongs_to :product
  12. 1 belongs_to :project
  13. 1 belongs_to :arch
  14. 1 belongs_to :user
  15. # see: Issue #6
  16. 1 before_validation -> { self.arch_id = Arch.find_by(name: 'x86_64').id }, on: :create
  17. # field "not_delete" can be changed only if build has been completed
  18. 1 before_validation -> { self.not_delete = false unless build_completed?; true }
  19. 1 validates :product, :product_id,
  20. :project, :project_id,
  21. :main_script,
  22. :arch, :arch_id,
  23. presence: true
  24. 1 validates :main_script, :params, length: { maximum: 255 }
  25. 1 attr_accessor :base_url, :product_name
  26. 1 attr_readonly :product_id
  27. 1 serialize :results, Array
  28. 1 scope :default_order, -> { order(updated_at: :desc) }
  29. 1 scope :for_user, -> (user) { where(user_id: user.id) }
  30. 1 scope :scoped_to_product_name, -> (product_name) {
  31. joins(:product).where('products.name LIKE ?', "%#{product_name}%") if product_name.present?
  32. }
  33. 1 scope :recent, -> { order(updated_at: :desc) }
  34. 1 scope :outdated, -> {
  35. where(not_delete: false).
  36. where("(#{table_name}.created_at < ? AND #{table_name}.autostarted is TRUE) OR #{table_name}.created_at < ?",
  37. Time.now - LIVE_TIME, Time.now - MAX_LIVE_TIME)
  38. }
  39. 1 after_initialize :init_project, if: :new_record?
  40. 1 def event_log_message
  41. {product: product.name}.inspect
  42. end
  43. 1 protected
  44. 1 def init_project
  45. self.project ||= product.try(:project)
  46. end
  47. end

app/models/project.rb

41.12% lines covered

214 relevant lines. 88 lines covered and 126 lines missed.
    
  1. 1 class Project < ActiveRecord::Base
  2. 1 has_ancestry orphan_strategy: :adopt # we replace a 'path' method in the Git module
  3. 1 include Autostart
  4. 1 include Owner
  5. 1 include Git
  6. 1 include Wiki
  7. 1 include UrlHelper
  8. 1 include EventLoggable
  9. 1 include Project::DefaultBranch
  10. 1 include Project::Finders
  11. 1 VISIBILITIES = ['open', 'hidden']
  12. 1 MAX_OWN_PROJECTS = 32000
  13. 1 NAME_REGEXP = /[\w\-\+\.]+/
  14. 1 OWNER_AND_NAME_REGEXP = /#{User::NAME_REGEXP.source}\/#{NAME_REGEXP.source}/
  15. 1 self.per_page = 25
  16. 1 belongs_to :owner, polymorphic: true, counter_cache: :own_projects_count
  17. 1 belongs_to :maintainer, class_name: 'User', optional: true
  18. 1 belongs_to :alias_from, class_name: 'Project', optional: true
  19. 1 has_many :aliases, class_name: 'Project', foreign_key: 'alias_from_id'
  20. 1 has_many :issues, dependent: :destroy
  21. 1 has_many :pull_requests, dependent: :destroy, foreign_key: 'to_project_id'
  22. 1 has_many :labels, dependent: :destroy
  23. 1 has_many :project_imports, dependent: :destroy
  24. 1 has_many :project_to_repositories, dependent: :destroy
  25. 1 has_many :repositories, through: :project_to_repositories
  26. 1 has_many :project_tags, dependent: :destroy
  27. 1 has_many :project_statistics, dependent: :destroy
  28. 1 has_many :build_lists, dependent: :destroy
  29. 1 has_many :hooks, dependent: :destroy
  30. 1 has_many :relations, as: :target, dependent: :destroy
  31. 1 has_many :collaborators, through: :relations, source: :actor, source_type: 'User'
  32. 1 has_many :groups, through: :relations, source: :actor, source_type: 'Group'
  33. 1 has_many :packages, class_name: 'BuildList::Package', dependent: :destroy
  34. 1 has_and_belongs_to_many :advisories # should be without dependent: :destroy
  35. 1 validates :name, uniqueness: { scope: [:owner_id, :owner_type], case_sensitive: false },
  36. presence: true,
  37. format: { with: /\A#{NAME_REGEXP.source}\z/,
  38. message: I18n.t("activerecord.errors.project.uname") },
  39. length: { maximum: 100 }
  40. 1 validates :maintainer, presence: true, unless: :new_record?
  41. 1 validates :url, presence: true, format: { with: /\Ahttps?:\/\/[\S]+\z/ }, if: :mass_import
  42. 1 validates :add_to_repository_id, presence: true, if: :mass_import
  43. 1 validates :visibility, presence: true, inclusion: { in: VISIBILITIES }
  44. 4 validate { errors.add(:base, :can_have_less_or_equal, count: MAX_OWN_PROJECTS) if owner.projects.size >= MAX_OWN_PROJECTS }
  45. # throws validation error message from ProjectToRepository model into Project model
  46. 1 validate do |project|
  47. 3 project.project_to_repositories.each do |p_to_r|
  48. next if p_to_r.valid?
  49. p_to_r.errors.map(&:full_message).each{ |msg| errors[:base] << msg }
  50. end
  51. 3 errors.delete :project_to_repositories
  52. end
  53. 1 attr_readonly :owner_id, :owner_type
  54. 1 before_validation :truncate_name, on: :create
  55. 4 before_save -> { self.owner_uname = owner.uname if owner_uname.blank? || owner_id_changed? || owner_type_changed? }
  56. 1 before_create :set_maintainer
  57. 1 after_save :attach_to_personal_repository
  58. 1 before_update -> { update_path_to_project(name_was) }, if: :name_changed?
  59. 1 attr_accessor :url, :srpms_list, :mass_import, :add_to_repository_id
  60. 1 def init_mass_import
  61. Project.perform_later :low, :run_mass_import, url, srpms_list, visibility, owner, add_to_repository_id
  62. end
  63. 1 def name_with_owner
  64. 30 "#{owner_uname || owner.uname}/#{name}"
  65. end
  66. 1 def to_param
  67. name_with_owner
  68. end
  69. 1 def all_members(*includes)
  70. members(includes) | (owner_type == 'User' ? [owner] : owner.members.includes(includes))
  71. end
  72. 1 def members(*includes)
  73. collaborators.includes(includes) | groups.map{ |g| g.members.includes(includes) }.flatten
  74. end
  75. 1 def add_member(member, role = 'admin')
  76. Relation.add_member(member, self, role)
  77. end
  78. 1 def remove_member(member)
  79. Relation.remove_member(member, self)
  80. end
  81. 1 def platforms
  82. @platforms ||= repositories.map(&:platform).uniq
  83. end
  84. 1 def admins
  85. admins = self.collaborators.where("relations.role = 'admin'")
  86. grs = self.groups.where("relations.role = 'admin'")
  87. if self.owner.is_a? Group
  88. grs = grs.where("relations.actor_id != ?", self.owner.id)
  89. admins = admins | owner.members.where("relations.role = 'admin'")
  90. end
  91. admins = admins | grs.map(&:members).flatten # member of the admin group is admin
  92. end
  93. 1 def public?
  94. 1 visibility == 'open'
  95. end
  96. 1 def owner?(user)
  97. owner == user
  98. end
  99. 1 def git_project_address auth_user
  100. opts = default_url_options
  101. opts.merge!({user: auth_user.authentication_token, password: ''}) unless self.public?
  102. Rails.application.routes.url_helpers.project_url(self.name_with_owner, opts) + '.git'
  103. #path #share by NFS
  104. end
  105. 1 def build_for(mass_build, repository_id, arch = Arch.find_by(name: 'i586'), priority = 0, increase_rt = false)
  106. build_for_platform = mass_build.build_for_platform
  107. save_to_platform = mass_build.save_to_platform
  108. user = mass_build.user
  109. # Select main and project platform repository(contrib, non-free and etc)
  110. # If main does not exist, will connect only project platform repository
  111. # If project platform repository is main, only main will be connect
  112. main_rep_id = build_for_platform.repositories.main.first.try(:id)
  113. include_repos = ([main_rep_id] << (save_to_platform.main? ? repository_id : nil)).compact.uniq
  114. project_version = project_version_for save_to_platform, build_for_platform
  115. increase_release_tag(project_version, user, "MassBuild##{mass_build.id}: Increase release tag") if increase_rt
  116. build_list = build_lists.build do |bl|
  117. bl.save_to_platform = save_to_platform
  118. bl.build_for_platform = build_for_platform
  119. bl.update_type = 'newpackage'
  120. bl.arch = arch
  121. bl.project_version = project_version
  122. bl.user = user
  123. bl.auto_publish_status = mass_build.auto_publish_status
  124. bl.auto_create_container = mass_build.auto_create_container
  125. bl.include_repos = include_repos
  126. bl.extra_repositories = mass_build.extra_repositories
  127. bl.extra_build_lists = mass_build.extra_build_lists
  128. bl.priority = priority
  129. bl.mass_build_id = mass_build.id
  130. bl.save_to_repository_id = repository_id
  131. bl.include_testing_subrepository = mass_build.include_testing_subrepository?
  132. bl.use_cached_chroot = mass_build.use_cached_chroot?
  133. bl.use_extra_tests = mass_build.use_extra_tests?
  134. bl.external_nodes = mass_build.external_nodes
  135. end
  136. build_list.save
  137. end
  138. 1 def fork(new_owner, new_name: nil, is_alias: false)
  139. new_name = new_name.presence || name
  140. dup.tap do |c|
  141. c.name = new_name
  142. c.parent_id = id
  143. c.alias_from_id = is_alias ? (alias_from_id || id) : nil
  144. c.owner = new_owner
  145. c.updated_at = nil; c.created_at = nil # :id = nil
  146. # Hack to call protected method :)
  147. c.send :set_maintainer
  148. c.save
  149. end
  150. end
  151. 1 def get_project_tag_sha1(tag, format)
  152. format_id = ProjectTag::FORMATS["#{tag_file_format(format)}"]
  153. project_tag = project_tags.where(tag_name: tag.name, format_id: format_id).first
  154. return project_tag.sha1 if project_tag && project_tag.commit_id == tag.commit.id && FileStoreService::File.new(sha1: project_tag.sha1).exist?
  155. archive = archive_by_treeish_and_format tag.name, format
  156. sha1 = FileStoreService::File.new(data: archive).save
  157. return nil if sha1.blank?
  158. if project_tag
  159. project_tag.destroy_files_from_file_store(project_tag.sha1)
  160. project_tag.update(sha1: sha1)
  161. else
  162. project_tags.create(
  163. tag_name: tag.name,
  164. format_id: format_id,
  165. commit_id: tag.commit.id,
  166. sha1: sha1
  167. )
  168. end
  169. return sha1
  170. end
  171. 1 def archive_by_treeish_and_format(treeish, format)
  172. @archive ||= create_archive treeish, format
  173. end
  174. # Finds release tag and increase its:
  175. # 'Release: %mkrel 4mdk' => 'Release: 5mdk'
  176. # 'Release: 4' => 'Release: 5'
  177. # Finds release macros and increase it:
  178. # '%define release %mkrel 4mdk' => '%define release 5mdk'
  179. # '%define release 4' => '%define release 5'
  180. 1 def self.replace_release_tag(content)
  181. build_new_release = Proc.new do |release, combine_release|
  182. if combine_release.present?
  183. r = combine_release.split('.').last.to_i
  184. release << combine_release.gsub(/.[\d]+$/, '') << ".#{r + 1}"
  185. else
  186. release = release.to_i + 1
  187. end
  188. release
  189. end
  190. content.gsub(/^Release:(\s+)(%mkrel\s+)?(\d+)([.\d]+)?(mdk)?$/) do |line|
  191. tab, mkrel, mdk = $1, $2, $5
  192. "Release:#{tab}#{build_new_release.call($3, $4)}#{mdk}"
  193. end.gsub(/^%define\s+release:?(\s+)(%mkrel\s+)?(\d+)([.\d]+)?(mdk)?$/) do |line|
  194. tab, mkrel, mdk = $1, $2, $5
  195. "%define release#{tab}#{build_new_release.call($3, $4)}#{mdk}"
  196. end
  197. end
  198. 1 class << self
  199. 1 Autostart::HUMAN_AUTOSTART_STATUSES.each do |autostart_status, human_autostart_status|
  200. 3 define_method "autostart_build_lists_#{human_autostart_status}" do
  201. autostart_build_lists autostart_status
  202. end
  203. end
  204. end
  205. 1 def self.autostart_build_lists(autostart_status)
  206. Project.where(autostart_status: autostart_status).find_each do |p|
  207. p.project_to_repositories.autostart_enabled.includes(repository: :platform).each do |p_to_r|
  208. repository = p_to_r.repository
  209. user = User.find(p_to_r.user_id)
  210. if repository.platform.personal?
  211. platforms = Platform.availables_main_platforms(user)
  212. else
  213. platforms = [repository.platform]
  214. end
  215. platforms.each do |platform|
  216. platform.platform_arch_settings.by_default.pluck(:arch_id).each do |arch_id|
  217. build_list = p.build_lists.build do |bl|
  218. bl.save_to_platform = repository.platform
  219. bl.build_for_platform = platform
  220. bl.update_type = BuildList::UPDATE_TYPE_NEWPACKAGE
  221. bl.arch_id = arch_id
  222. bl.project_version = p.project_version_for(repository.platform, platform)
  223. bl.user = user
  224. bl.auto_publish_status = p_to_r.auto_publish? ? BuildList::AUTO_PUBLISH_STATUS_DEFAULT : BuildList::AUTO_PUBLISH_STATUS_NONE
  225. bl.save_to_repository = repository
  226. bl.include_repos = [platform.repositories.main.first.try(:id)].compact
  227. if repository.platform.personal?
  228. bl.extra_repositories = [repository.id]
  229. else
  230. bl.include_repos |= [repository.id]
  231. end
  232. end
  233. build_list.save
  234. end
  235. end
  236. end
  237. end
  238. end
  239. 1 def increase_release_tag(project_version, user, message)
  240. blob, raw = find_blob_and_raw_of_spec_file(project_version)
  241. return unless blob
  242. content = self.class.replace_release_tag raw.content
  243. return if content == raw.content
  244. update_file(blob.name, content.gsub("\r", ''),
  245. message: message,
  246. actor: user,
  247. head: project_version
  248. )
  249. end
  250. 1 protected
  251. 1 def create_archive(treeish, format)
  252. file_name = "#{name}-#{treeish}"
  253. fullname = "#{file_name}.#{tag_file_format(format)}"
  254. file = Tempfile.new fullname, File.join(Rails.root, 'tmp')
  255. system("cd #{path}; git archive --format=#{format == 'zip' ? 'zip' : 'tar'} --prefix=#{file_name}/ #{treeish} #{format == 'zip' ? '' : ' | gzip -9'} > #{file.path}")
  256. file.close
  257. {
  258. path: file.path,
  259. fullname: fullname
  260. }
  261. end
  262. 1 def tag_file_format(format)
  263. format == 'zip' ? 'zip' : 'tar.gz'
  264. end
  265. 1 def truncate_name
  266. 3 self.name = name.strip if name
  267. end
  268. 1 def attach_to_personal_repository
  269. 3 owner_repos = self.owner.personal_platform.repositories
  270. 3 if is_package
  271. 3 repositories << self.owner.personal_repository unless repositories.exists?(id: owner_repos.pluck(:id))
  272. else
  273. repositories.delete owner_repos
  274. end
  275. end
  276. 1 def set_maintainer
  277. 3 if maintainer_id.blank?
  278. 3 self.maintainer_id = (owner_type == 'User') ? self.owner_id : self.owner.owner_id
  279. end
  280. end
  281. 1 def update_path_to_project(old_name)
  282. new_name, new_path = name, path
  283. self.name = old_name
  284. old_path = path
  285. self.name = new_name
  286. FileUtils.mv old_path, new_path, force: true if Dir.exists?(old_path)
  287. pull_requests_old_path = File.join(APP_CONFIG['git_path'], 'pull_requests', owner.uname, old_name)
  288. if Dir.exists?(pull_requests_old_path)
  289. FileUtils.mv pull_requests_old_path,
  290. File.join(APP_CONFIG['git_path'], 'pull_requests', owner.uname, new_name),
  291. force: true
  292. end
  293. PullRequest.where(from_project_id: id).update_all(from_project_name: new_name)
  294. PullRequest.where(from_project_id: id).each{ |p| p.update_relations(old_name) }
  295. pull_requests.where('from_project_id != to_project_id').each(&:update_relations)
  296. end
  297. 1 later :update_path_to_project, queue: :middle
  298. end

app/models/project_import.rb

100.0% lines covered

7 relevant lines. 7 lines covered and 0 lines missed.
    
  1. 1 class ProjectImport < ActiveRecord::Base
  2. 1 belongs_to :project
  3. 1 belongs_to :platform
  4. 1 validates :name, uniqueness: { scope: :platform_id, case_sensitive: false }
  5. 1 validates :name, :platform, :version, presence: true
  6. 1 scope :by_name, ->(name) { where("#{table_name}.name ILIKE ?", name) }
  7. 1 after_initialize ->(r) { r.file_mtime ||= Time.current - 10.years } # default
  8. end

app/models/project_statistic.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. 1 class ProjectStatistic < ActiveRecord::Base
  2. 1 belongs_to :arch
  3. 1 belongs_to :project
  4. 1 validates :arch, :project, :average_build_time, :build_count, presence: true
  5. 1 validates :project_id, uniqueness: { scope: :arch_id }
  6. end

app/models/project_tag.rb

87.5% lines covered

8 relevant lines. 7 lines covered and 1 lines missed.
    
  1. 1 class ProjectTag < ActiveRecord::Base
  2. 1 include FileStoreClean
  3. 1 FORMATS = {
  4. 'zip' => 0,
  5. 'tar.gz' => 1
  6. }
  7. 1 belongs_to :project
  8. 1 validates :project, :commit_id, :sha1, :tag_name, :format_id, presence: true
  9. 1 validates :project_id, uniqueness: { scope: [:tag_name, :format_id] }
  10. 1 def sha1_of_file_store_files
  11. [sha1]
  12. end
  13. end

app/models/project_to_repository.rb

80.0% lines covered

20 relevant lines. 16 lines covered and 4 lines missed.
    
  1. 1 class ProjectToRepository < ActiveRecord::Base
  2. 1 AUTOSTART_OPTIONS = %w(auto_publish user_id enabled)
  3. 1 belongs_to :project
  4. 1 belongs_to :repository
  5. 1 delegate :path, to: :project
  6. 1 scope :autostart_enabled, -> { where("autostart_options -> 'enabled' = 'true'") }
  7. 1 after_destroy :destroy_project_from_repository, unless: -> { Thread.current[:skip] }
  8. 1 validate :one_project_in_platform_repositories, on: :create
  9. 1 AUTOSTART_OPTIONS.each do |field|
  10. 3 store_accessor :autostart_options, field
  11. end
  12. 1 def enabled?
  13. ['true', true].include?(enabled)
  14. end
  15. 1 def auto_publish?
  16. ['true', true].include?(auto_publish)
  17. end
  18. 1 protected
  19. 1 def destroy_project_from_repository
  20. DestroyProjectFromRepositoryJob.perform(project, repository)
  21. end
  22. 1 def one_project_in_platform_repositories
  23. 6 if Project.joins(repositories: :platform).where('platforms.id = ?', repository.platform_id).by_name(project.name).exists?
  24. errors.add(:base, I18n.t('activerecord.errors.project_to_repository.project'))
  25. end
  26. end
  27. end

app/models/pull_request.rb

37.5% lines covered

144 relevant lines. 54 lines covered and 90 lines missed.
    
  1. 1 class PullRequest < ActiveRecord::Base
  2. STATUSES = [
  3. 1 STATUS_OPEN = 'open',
  4. STATUS_READY = 'ready',
  5. STATUS_ALREADY = 'already',
  6. STATUS_BLOCKED = 'blocked',
  7. STATUS_MERGED = 'merged',
  8. STATUS_CLOSED = 'closed'
  9. ]
  10. 1 belongs_to :issue,
  11. autosave: true,
  12. dependent: :destroy,
  13. touch: true,
  14. validate: true
  15. 1 belongs_to :to_project,
  16. class_name: 'Project',
  17. foreign_key: 'to_project_id'
  18. 1 belongs_to :from_project,
  19. class_name: 'Project',
  20. foreign_key: 'from_project_id'
  21. 1 delegate :user,
  22. :user_id,
  23. :title,
  24. :body,
  25. :serial_id,
  26. :assignee,
  27. :status,
  28. :to_param,
  29. :created_at,
  30. :updated_at,
  31. :comments,
  32. :status=,
  33. to: :issue, allow_nil: true
  34. 1 validates :from_project, presence: true, on: :create
  35. 1 validates :to_project, presence: true
  36. 1 validate :uniq_merge, if: ->(pull) { pull.to_project.present? }
  37. 1 validates_each :from_ref, :to_ref do |record, attr, value|
  38. check_ref record, attr, value
  39. end
  40. 1 before_create :clean_dir
  41. 1 before_create :set_add_data
  42. 1 after_destroy :clean_dir
  43. 1 accepts_nested_attributes_for :issue
  44. 1 scope :needed_checking, -> { includes(:issue).where(issues: { status: [STATUS_OPEN, STATUS_BLOCKED, STATUS_READY] }) }
  45. 1 scope :not_closed_or_merged, -> { needed_checking }
  46. 1 scope :closed_or_merged, -> { where(issues: { status: [STATUS_CLOSED, STATUS_MERGED] }) }
  47. 1 state_machine :status, initial: :open do
  48. 1 event :ready do
  49. 1 transition [:ready, :open, :blocked] => :ready
  50. end
  51. 1 event :already do
  52. 1 transition [:ready, :open, :blocked] => :already
  53. end
  54. 1 event :block do
  55. 1 transition [:ready, :open, :blocked] => :blocked
  56. end
  57. 1 event :merging do
  58. 1 transition ready: :merged
  59. end
  60. 1 event :close do
  61. 1 transition [:ready, :open, :blocked] => :closed
  62. end
  63. 1 event :reopen do
  64. 1 transition closed: :open
  65. end
  66. end
  67. 1 def update_relations(old_from_project_name = nil)
  68. FileUtils.mv path(old_from_project_name), path, force: true if old_from_project_name
  69. return unless Dir.exists?(path)
  70. system 'git', '-C', path, 'remote', 'set-url', 'origin', to_project.path
  71. system 'git', '-C', path, 'remote', 'set-url', 'head', from_project.path if cross_pull?
  72. end
  73. 1 later :update_relations, queue: :middle
  74. 1 def cross_pull?
  75. from_project_id != to_project_id
  76. end
  77. 1 def check(do_transaction = true)
  78. if do_transaction && !valid?
  79. issue.set_close nil
  80. issue.save(validate: false) # FIXME remove this hack
  81. return false
  82. end
  83. res = merge
  84. new_status = case res
  85. when /Already up-to-date/, /Already up to date/
  86. 'already'
  87. when /Merge made by/
  88. system("cd #{path} && git reset --hard HEAD^") # remove merge commit
  89. 'ready'
  90. when /Automatic merge failed/
  91. system("cd #{path} && git reset --hard HEAD") # clean git index
  92. 'block'
  93. else
  94. raise res
  95. end
  96. if do_transaction
  97. new_status == 'already' ? (ready; merging) : send(new_status)
  98. self.update_inline_comments
  99. else
  100. self.status = new_status == 'block' ? STATUS_BLOCKED : new_status
  101. end
  102. end
  103. 1 def merge!(who)
  104. return false unless can_merging?
  105. old_commit = to_project.repo.commits(to_ref).first
  106. commit = repo.commits(to_ref).first
  107. system "git -C #{path} config user.name \"#{who.uname}\" && git -C #{path} config user.email \"#{who.email}\""
  108. res = merge
  109. if commit.id != repo.commits(to_ref).first.id
  110. res2 = %x(export GL_ID=user-#{who.id} GL_REPO_NAME=#{to_project.path} && git -C #{path} push origin HEAD)
  111. system("git -C #{path} reset --hard HEAD^") # for diff maybe FIXME
  112. if old_commit.id == to_project.repo.commits(to_ref).first.id
  113. raise "merge result pull_request #{id}: #{$?.exitstatus}; #{res2}; #{res}"
  114. end
  115. set_user_and_time who
  116. merging
  117. else # Try to catch no merge errors
  118. raise "merge result pull_request #{id}: #{res}"
  119. end
  120. end
  121. 1 def path(suffix = from_project_name)
  122. last_part = [id, from_project_owner_uname, suffix].compact.join('-')
  123. File.join(APP_CONFIG['git_path'], "#{new_record? ? 'temp_' : ''}pull_requests", to_project.owner.uname, to_project.name, last_part)
  124. end
  125. 1 def from_branch
  126. cross_pull? ? "head_#{from_ref}" : from_ref
  127. end
  128. 1 def common_ancestor
  129. return @common_ancestor if @common_ancestor
  130. base_commit = repo.commits(to_ref).first
  131. @common_ancestor = repo.commit(repo.git.merge_base({}, base_commit, from_commit)) || base_commit
  132. end
  133. 1 alias_method :to_commit, :common_ancestor
  134. 1 def diff_stats
  135. @diff_stats ||= repo.diff_stats(to_commit.id, from_commit.id)
  136. end
  137. 1 def diff
  138. @diff ||= repo.diff(to_commit.id, from_commit.id)
  139. end
  140. 1 def set_user_and_time user
  141. issue.closed_at = Time.now.utc
  142. issue.closer = user
  143. end
  144. 1 def self.check_ref(record, attr, value)
  145. project = attr == :from_ref ? record.from_project : record.to_project
  146. return if project.blank?
  147. if record.to_project.repo.branches.count > 0
  148. record.errors.add attr, I18n.t('projects.pull_requests.wrong_ref') unless project.repo.branches_and_tags.map(&:name).include?(value)
  149. else
  150. record.errors.add attr, I18n.t('projects.pull_requests.empty_repo')
  151. end
  152. end
  153. 1 def uniq_merge
  154. if to_project && to_project.pull_requests.needed_checking
  155. .where(from_project_id: from_project_id,
  156. to_ref: to_ref, from_ref: from_ref)
  157. .where('pull_requests.id <> :id or :id is null', id: id).count > 0
  158. errors.add(:base_branch, I18n.t('projects.pull_requests.duplicate', from_ref: from_ref))
  159. end
  160. end
  161. 1 def repo
  162. @repo ||= Grit::Repo.new(path)
  163. end
  164. 1 def from_commit
  165. repo.commits(from_branch).first
  166. end
  167. 1 protected
  168. 1 def system(*args)
  169. Kernel.system(*args)
  170. end
  171. 1 def merge
  172. clone
  173. message = "Merge pull request ##{serial_id} from #{from_project_owner_uname}/#{from_project_name}:#{from_ref}\r\n #{title}"
  174. %x(cd #{path} && git checkout #{to_ref.shellescape} && git merge --no-ff #{from_branch.shellescape} -m #{message.shellescape})
  175. end
  176. 1 def clone
  177. return if from_project.nil?
  178. git = Grit::Git.new(path)
  179. if new_record? || !git.exist?
  180. #~ FileUtils.mkdir_p(path)
  181. #~ system("git clone --local --no-hardlinks #{to_project.path} #{path}")
  182. options = {bare: false, shared: false, branch: to_ref} # shared?
  183. `rm -rf #{path}`
  184. git.fs_mkdir('..')
  185. git.clone(options, to_project.path, path)
  186. if cross_pull?
  187. system 'git', '-C', path, 'remote', 'add', 'head', from_project.path
  188. end
  189. #clean # Need testing
  190. end
  191. system 'git', '-C', path, 'tag', '-d', from_ref, to_ref
  192. system "git -C #{path} fetch --tags && git -C #{path} fetch --all"
  193. tags, head = repo.tags.map(&:name), to_project == from_project ? 'origin' : 'head'
  194. system 'git', '-C', path, 'checkout', to_ref
  195. unless tags.include? to_ref
  196. system 'git', '-C', path, 'reset', '--hard', "origin/#{to_ref}"
  197. end
  198. unless tags.include? from_ref
  199. system 'git', '-C', path, 'branch', '-D', from_branch
  200. system 'git', '-C', path, 'fetch', head, "+#{from_ref}:#{from_branch}"
  201. system 'git', '-C', path, 'checkout', to_ref
  202. end
  203. end
  204. 1 def clean
  205. to_project.repo.branches.each {|branch| system 'git', 'checkout', branch.name}
  206. system 'git', '-C', path, 'checkout', to_ref
  207. to_project.repo.branches.each do |branch|
  208. system 'git', '-C', path, 'branch', '-D', branch.name unless [to_ref, from_branch].include? branch.name
  209. end
  210. to_project.repo.tags.each do |tag|
  211. system 'git', '-C', path, 'tag', '-d', tag.name unless [to_ref, from_branch].include? tag.name
  212. end
  213. end
  214. 1 def clean_dir
  215. FileUtils.rm_rf path
  216. end
  217. 1 def update_inline_comments
  218. self.comments.each do |c|
  219. if c.data.present? # maybe need add new column 'actual'?
  220. c.actual_inline_comment? diff, true
  221. c.save
  222. end
  223. end
  224. end
  225. 1 def set_add_data
  226. self.from_project_owner_uname = from_project.owner.uname
  227. self.from_project_name = from_project.name
  228. end
  229. end

app/models/relation.rb

52.94% lines covered

34 relevant lines. 18 lines covered and 16 lines missed.
    
  1. 1 class Relation < ActiveRecord::Base
  2. 1 ROLES = %w[reader writer admin]
  3. 1 belongs_to :target, polymorphic: true
  4. 1 belongs_to :actor, polymorphic: true, touch: true
  5. 1 validates :role, inclusion: { in: ROLES }
  6. 1 validates :target,
  7. presence: true
  8. 1 validates :actor,
  9. presence: true
  10. # validate { errors.add(:actor, :taken) if Relation.where(actor_type: self.actor_type, actor_id: self.actor_id).present? }
  11. 1 before_validation :add_default_role
  12. 1 scope :by_user_through_groups, ->(u) {
  13. where("actor_type = 'User' AND actor_id = ? OR actor_type = 'Group' AND actor_id IN (?)", u.id, u.group_ids)
  14. }
  15. 1 scope :by_actor, ->(obj) { where(actor_id: obj.id, actor_type: obj.class.to_s) }
  16. 1 scope :by_target, ->(tar) { where(target_id: tar.id, target_type: tar.class.to_s) }
  17. 1 scope :by_role, ->(role) { where(role: role) }
  18. 1 def self.create_with_role(actor, target, role)
  19. r = self.new
  20. r.actor = actor
  21. r.target = target
  22. r.role = role
  23. r.save
  24. end
  25. 1 def self.add_member(member, target, role, relation = :relations)
  26. if target.send(relation).exists?(actor_id: member.id, actor_type: member.class.to_s) || (target.respond_to?(:owner) && target.owner == member)
  27. true
  28. else
  29. rel = target.send(relation).build(role: role)
  30. rel.actor = member
  31. rel.save
  32. end
  33. end
  34. 1 def self.remove_member(member, target)
  35. return false if target.respond_to?(:owner) && target.owner == member
  36. res = Relation.by_actor(member).by_target(target).each{|r| r.destroy}
  37. if member.is_a?(User) && ['Project', 'Group'].include?(target.class.name)
  38. member.check_assigned_issues target
  39. end
  40. res
  41. end
  42. 1 protected
  43. 1 def add_default_role
  44. 42 self.role = ROLES.first if role.nil? || role.empty?
  45. end
  46. end

app/models/repository.rb

48.11% lines covered

106 relevant lines. 51 lines covered and 55 lines missed.
    
  1. 1 class Repository < ActiveRecord::Base
  2. 1 extend FriendlyId
  3. 1 friendly_id :name, use: [:finders]
  4. 1 include EventLoggable
  5. 1 include EmptyMetadata
  6. 1 LOCK_FILE_NAMES = { sync: '.sync.lock', repo: '.repo.lock' }
  7. 1 SORT = { 'base' => 1, 'main' => 2, 'contrib' => 3, 'non-free' => 4, 'restricted' => 5 }
  8. 1 belongs_to :platform
  9. 1 has_many :relations, as: :target, dependent: :destroy
  10. 1 has_many :actors, as: :target, class_name: 'Relation', dependent: :destroy
  11. 1 has_many :members, through: :actors, source: :actor, source_type: 'User'
  12. 1 has_many :project_to_repositories, dependent: :destroy, validate: true
  13. 1 has_many :projects, through: :project_to_repositories
  14. 1 has_many :repository_statuses, dependent: :destroy
  15. 1 has_one :key_pair, dependent: :destroy
  16. 1 has_many :build_lists, foreign_key: :save_to_repository_id, dependent: :destroy
  17. 1 validates :description, presence: true,
  18. length: { maximum: 100 }
  19. 1 validates :name, uniqueness: { scope: :platform_id, case_sensitive: false },
  20. presence: true,
  21. format: { with: /\A[a-z0-9_\-]+\z/ },
  22. length: { maximum: 100 }
  23. 1 validates :publish_builds_only_from_branch, length: { maximum: 255 }
  24. 1 scope :recent, -> { order(:name) }
  25. 1 scope :main, -> { where(name: %w(main base)) }
  26. 1 before_destroy :detele_directory
  27. 1 attr_readonly :name, :platform_id
  28. 1 attr_accessor :projects_list, :build_for_platform_id, :resign_rpms
  29. 1 def regenerate(build_for_platform_id = nil, resign_rpms = false)
  30. build_for_platform = Platform.main.find build_for_platform_id if platform.personal?
  31. status = repository_statuses.find_or_create_by(platform_id: build_for_platform.try(:id) || platform_id)
  32. status.resign_rpms = resign_rpms
  33. status.save
  34. status.regenerate
  35. end
  36. 1 def resign
  37. if platform.main?
  38. status = repository_statuses.find_or_create_by(platform_id: platform_id)
  39. status.resign
  40. end
  41. end
  42. 1 def base_clone(attrs = {})
  43. dup.tap do |c|
  44. c.platform_id = nil
  45. attrs.each {|k,v| c.send("#{k}=", v)}
  46. c.updated_at = nil; c.created_at = nil
  47. end
  48. end
  49. 1 def clone_relations(from)
  50. with_skip do
  51. from.projects.find_each {|p| self.projects << p if self.projects.exclude?(p)}
  52. end
  53. end
  54. 1 later :clone_relations, loner: true, queue: :low
  55. 1 def add_projects(list, user)
  56. list.lines.each do |line|
  57. begin
  58. line.chomp!; line.strip!
  59. owner, name = line.split('/')
  60. next if owner.blank? || name.blank?
  61. project = ProjectPolicy::Scope.new(user, Project).read.where(owner_uname: owner, name: name).first
  62. projects << project if project
  63. rescue RuntimeError, Exception
  64. end
  65. end
  66. end
  67. 1 later :add_projects, queue: :middle
  68. 1 def remove_projects(list)
  69. list.lines.each do |name|
  70. begin
  71. name.chomp!; name.strip!
  72. next if name.blank?
  73. project_to_repositories.where(projects: { name: name }).joins(:project).readonly(false).destroy_all
  74. rescue RuntimeError, Exception
  75. end
  76. end
  77. end
  78. 1 later :remove_projects, queue: :middle
  79. 1 def full_clone(attrs = {})
  80. base_clone(attrs).tap do |c|
  81. with_skip {c.save} and c.clone_relations(self) # later with resque
  82. end
  83. end
  84. # Checks locking of sync
  85. 1 def sync_lock_file_exists?
  86. lock_file_actions :check, :sync
  87. end
  88. # Uses for locking sync
  89. # Calls from UI
  90. 1 def add_sync_lock_file
  91. lock_file_actions :add, :sync
  92. end
  93. # Uses for unlocking sync
  94. # Calls from UI
  95. 1 def remove_sync_lock_file
  96. lock_file_actions :remove, :sync
  97. end
  98. # Uses for locking publishing
  99. # Calls from API
  100. 1 def add_repo_lock_file
  101. lock_file_actions :add, :repo
  102. end
  103. # Uses for unlocking publishing
  104. # Calls from API
  105. 1 def remove_repo_lock_file
  106. lock_file_actions :remove, :repo
  107. end
  108. # Presence of `.repo.lock` file means that mirror is currently synchronising the repository state.
  109. 1 def repo_lock_file_exists?
  110. lock_file_actions :check, :repo
  111. end
  112. 1 def add_member(member, role = 'admin')
  113. Relation.add_member(member, self, role)
  114. end
  115. 1 def remove_member(member)
  116. Relation.remove_member(member, self)
  117. end
  118. 1 class << self
  119. 1 def build_stub(platform)
  120. rep = Repository.new
  121. rep.platform = platform
  122. rep
  123. end
  124. end
  125. 1 def destroy
  126. with_skip {super} # avoid cascade XML RPC requests
  127. end
  128. 1 later :destroy, queue: :low
  129. 1 def self.custom_sort(repos)
  130. repos.select{ |r| SORT.keys.include?(r.name) }.sort{ |a,b| SORT[a.name] <=> SORT[b.name] } | repos.sort_by(&:name)
  131. end
  132. 1 protected
  133. 1 def lock_file_actions(action, lock_file)
  134. result = false
  135. (['SRPMS'] << Arch.pluck(:name)).each do |arch|
  136. path = "#{platform.path}/repository/#{arch}/#{name}/#{LOCK_FILE_NAMES[lock_file]}"
  137. case action
  138. when :add
  139. result ||= FileUtils.touch(path) rescue nil
  140. when :remove
  141. result ||= FileUtils.rm_f(path)
  142. when :check
  143. return true if File.exist?(path)
  144. end
  145. end
  146. return result
  147. end
  148. 1 def detele_directory
  149. return unless platform
  150. repository_path = platform.path << '/repository'
  151. if platform.personal?
  152. Platform.main.pluck(:name).each do |main_platform_name|
  153. detele_repositories_directory "#{repository_path}/#{main_platform_name}"
  154. end
  155. else
  156. detele_repositories_directory repository_path
  157. end
  158. end
  159. 1 def detele_repositories_directory(repository_path)
  160. srpm_and_arches = (['SRPM'] << Arch.pluck(:name)).join(',')
  161. `sh -c 'rm -rf #{repository_path}/{#{srpm_and_arches}}/#{name}'`
  162. end
  163. end

app/models/repository_status.rb

100.0% lines covered

49 relevant lines. 49 lines covered and 0 lines missed.
    
  1. 1 class RepositoryStatus < ActiveRecord::Base
  2. 1 include FileStoreClean
  3. 1 include RegenerationStatus
  4. 1 WAITING_FOR_RESIGN = 300
  5. 1 PUBLISH = 400
  6. 1 RESIGN = 500
  7. 1 WAITING_FOR_RESIGN_AFTER_PUBLISH = 600
  8. 1 WAITING_FOR_RESIGN_AFTER_REGENERATION = 700
  9. 1 WAITING_FOR_REGENERATION_AFTER_PUBLISH = 800
  10. 1 WAITING_FOR_REGENERATION_AFTER_RESIGN = 900
  11. 1 WAITING_FOR_RESIGN_AND_REGENERATION_AFTER_PUBLISH = 1000
  12. 1 WAITING_FOR_RESIGN_AND_REGENERATION = 1100
  13. 1 HUMAN_STATUSES = HUMAN_STATUSES.clone.merge({
  14. WAITING_FOR_RESIGN => :waiting_for_resign,
  15. PUBLISH => :publish,
  16. RESIGN => :resign,
  17. WAITING_FOR_RESIGN_AFTER_PUBLISH => :waiting_for_resign_after_publish,
  18. WAITING_FOR_RESIGN_AFTER_REGENERATION => :waiting_for_resign_after_regeneration,
  19. WAITING_FOR_REGENERATION_AFTER_PUBLISH => :waiting_for_regeneration_after_publish,
  20. WAITING_FOR_REGENERATION_AFTER_RESIGN => :waiting_for_regeneration_after_resign,
  21. WAITING_FOR_RESIGN_AND_REGENERATION_AFTER_PUBLISH => :waiting_for_resign_and_regeneration_after_publish,
  22. WAITING_FOR_RESIGN_AND_REGENERATION => :waiting_for_resign_and_regeneration
  23. }).freeze
  24. 1 belongs_to :platform
  25. 1 belongs_to :repository
  26. 1 validates :repository, :platform, presence: true
  27. 1 validates :repository_id, uniqueness: { scope: :platform_id }
  28. 1 scope :platform_ready, -> { where(platforms: {status: READY}).joins(:platform) }
  29. 1 scope :for_regeneration, -> { where(status: WAITING_FOR_REGENERATION) }
  30. 1 scope :for_resign, -> { where(status: [WAITING_FOR_RESIGN, WAITING_FOR_RESIGN_AND_REGENERATION]) }
  31. 1 scope :not_ready, -> { where('repository_statuses.status != ?', READY) }
  32. 1 state_machine :status, initial: :ready do
  33. 1 event :ready do
  34. 1 transition [:regenerating, :publish, :resign] => :ready
  35. 1 transition [:waiting_for_resign_after_publish, :waiting_for_resign_after_regeneration] => :waiting_for_resign
  36. 1 transition [:waiting_for_regeneration_after_publish, :waiting_for_regeneration_after_resign] => :waiting_for_regeneration
  37. 1 transition waiting_for_resign_and_regeneration_after_publish: :waiting_for_resign_and_regeneration
  38. end
  39. 1 event :regenerate do
  40. 1 transition ready: :waiting_for_regeneration
  41. 1 transition publish: :waiting_for_regeneration_after_publish
  42. 1 transition resign: :waiting_for_regeneration_after_resign
  43. 1 transition waiting_for_resign_after_publish: :waiting_for_resign_and_regeneration_after_publish
  44. 1 transition waiting_for_resign: :waiting_for_resign_and_regeneration
  45. end
  46. 1 event :start_regeneration do
  47. 1 transition waiting_for_regeneration: :regenerating
  48. 1 transition waiting_for_resign_and_regeneration: :waiting_for_resign_after_regeneration
  49. end
  50. 1 event :resign do
  51. 1 transition ready: :waiting_for_resign
  52. 1 transition publish: :waiting_for_resign_after_publish
  53. 1 transition waiting_for_regeneration: :waiting_for_resign_and_regeneration
  54. 1 transition waiting_for_regeneration_after_publish: :waiting_for_resign_and_regeneration_after_publish
  55. 1 transition regenerating: :waiting_for_resign_after_regeneration
  56. end
  57. 1 event :start_resign do
  58. 1 transition waiting_for_resign: :resign
  59. 1 transition waiting_for_resign_and_regeneration: :waiting_for_regeneration_after_resign
  60. end
  61. 1 event :publish do
  62. 1 transition ready: :publish
  63. end
  64. 1 HUMAN_STATUSES.each do |code,name|
  65. 12 state name, value: code
  66. end
  67. end
  68. end

app/models/rpm_build_node.rb

65.22% lines covered

23 relevant lines. 15 lines covered and 8 lines missed.
    
  1. 1 require 'ohm'
  2. 1 require 'ohm/expire'
  3. 1 class RpmBuildNode < Ohm::Model
  4. 1 include Ohm::Expire
  5. 1 TTL = 120
  6. 1 expire TTL
  7. 1 attribute :user_id
  8. 1 attribute :worker_count
  9. 1 attribute :busy_workers
  10. 1 attribute :system
  11. 1 attribute :host
  12. 1 attribute :query_string
  13. 1 attribute :last_build_id
  14. 1 def user
  15. User.where(id: user_id).first
  16. end
  17. 1 def self.total_statistics
  18. systems, others, busy = 0, 0, 0
  19. RpmBuildNode.all.select{ |n| n.user_id }.each do |n|
  20. if n.system == 'true'
  21. systems += n.worker_count.to_i
  22. else
  23. others += n.worker_count.to_i
  24. end
  25. busy += n.busy_workers.to_i
  26. end
  27. { systems: systems, others: others, busy: busy }
  28. end
  29. end

app/models/search.rb

57.14% lines covered

14 relevant lines. 8 lines covered and 6 lines missed.
    
  1. 1 class Search < Struct.new(:query, :user, :paginate_params)
  2. 1 include ActiveModel::Conversion
  3. 1 extend ActiveModel::Naming
  4. 1 TYPES = %w(projects users groups platforms)
  5. 1 TYPES.each do |type|
  6. 4 define_method type do
  7. find_collection(type)
  8. end
  9. end
  10. 1 private
  11. 1 def find_collection(type)
  12. scope =
  13. if type == 'users'
  14. User.opened
  15. else
  16. klass = type.classify.constantize
  17. "#{klass}Policy::Scope".constantize.new(user, klass).show
  18. end
  19. scope.search_like(query).
  20. search_order.
  21. paginate(paginate_params)
  22. end
  23. end

app/models/settings_notifier.rb

100.0% lines covered

3 relevant lines. 3 lines covered and 0 lines missed.
    
  1. 1 class SettingsNotifier < ActiveRecord::Base
  2. 1 belongs_to :user
  3. 1 validates :user, presence: true
  4. end

app/models/ssh_key.rb

41.67% lines covered

36 relevant lines. 15 lines covered and 21 lines missed.
    
  1. # This class is based on
  2. # https://github.com/gitlabhq/gitlabhq/blob/15c0e58a49d623a0f8747e1d7e74364324eeb79f/app/models/key.rb
  3. 1 class SshKey < ActiveRecord::Base
  4. 1 SHELL_KEY_COMMAND = "/home/#{APP_CONFIG['shell_user']}/gitlab-shell/bin/gitlab-keys"
  5. 1 belongs_to :user
  6. 1 before_validation -> { self.key = key.strip if key.present? }
  7. 1 before_validation :set_fingerprint
  8. 1 validates :name, length: { maximum: 255 }
  9. 1 validates :key, length: { maximum: 5000 }, format: { with: /ssh-.{3} / } # Public key?
  10. 1 validates :fingerprint, uniqueness: true, presence: { message: I18n.t('activerecord.errors.ssh_key.wrong_key') }
  11. 1 after_create :add_key
  12. 1 before_destroy :remove_key
  13. 1 protected
  14. 1 def set_fingerprint
  15. return false unless key
  16. file = Tempfile.new('key_file', '/tmp')
  17. filename = file.path
  18. begin
  19. file.puts key
  20. file.rewind
  21. fingerprint_output = `ssh-keygen -lf #{file.path} 2>&1` # Catch stderr.
  22. exitstatus = $?.exitstatus
  23. ensure
  24. file.close
  25. file.unlink # deletes the temp file
  26. end
  27. if exitstatus != 0
  28. self.fingerprint = nil
  29. else
  30. self.fingerprint = fingerprint_output.split.try :[], 1
  31. if name.blank?
  32. s = fingerprint_output.split.try :[], 2
  33. if filename == s # no identificator
  34. start = key =~ /ssh-.{3} /
  35. self.name = key[start..start+26] # taken first 26 characters
  36. else
  37. self.name = s
  38. end
  39. end
  40. end
  41. end
  42. 1 def key_id
  43. "key-#{id}"
  44. end
  45. 1 def add_key
  46. system "#{SHELL_KEY_COMMAND} add-key #{key_id} \"#{key}\"" # Safety?
  47. end
  48. 1 def remove_key
  49. system "#{SHELL_KEY_COMMAND} rm-key #{key_id}"# \"#{key}\""
  50. end
  51. end

app/models/statistic.rb

91.67% lines covered

36 relevant lines. 33 lines covered and 3 lines missed.
    
  1. 1 class Statistic < ActiveRecord::Base
  2. KEYS = [
  3. 1 KEY_COMMIT = 'commit',
  4. KEY_BUILD_LIST = 'build_list',
  5. KEY_BUILD_LIST_BUILD_STARTED = "#{KEY_BUILD_LIST}.#{BuildList::BUILD_STARTED}",
  6. KEY_BUILD_LIST_SUCCESS = "#{KEY_BUILD_LIST}.#{BuildList::SUCCESS}",
  7. KEY_BUILD_LIST_BUILD_ERROR = "#{KEY_BUILD_LIST}.#{BuildList::BUILD_ERROR}",
  8. KEY_BUILD_LIST_BUILD_PUBLISHED = "#{KEY_BUILD_LIST}.#{BuildList::BUILD_PUBLISHED}",
  9. KEY_ISSUE = 'issue',
  10. KEY_ISSUES_OPEN = "#{KEY_ISSUE}.#{Issue::STATUS_OPEN}",
  11. KEY_ISSUES_REOPEN = "#{KEY_ISSUE}.#{Issue::STATUS_REOPEN}",
  12. KEY_ISSUES_CLOSED = "#{KEY_ISSUE}.#{Issue::STATUS_CLOSED}",
  13. KEY_PULL_REQUEST = 'pull_request',
  14. KEY_PULL_REQUESTS_OPEN = "#{KEY_PULL_REQUEST}.#{PullRequest::STATUS_OPEN}",
  15. KEY_PULL_REQUESTS_MERGED = "#{KEY_PULL_REQUEST}.#{PullRequest::STATUS_MERGED}",
  16. KEY_PULL_REQUESTS_CLOSED = "#{KEY_PULL_REQUEST}.#{PullRequest::STATUS_CLOSED}",
  17. ]
  18. 1 belongs_to :user
  19. 1 belongs_to :project
  20. 1 validates :user_id,
  21. uniqueness: { scope: [:project_id, :key, :activity_at] },
  22. presence: true
  23. 1 validates :email,
  24. presence: true
  25. 1 validates :project_id,
  26. presence: true
  27. 1 validates :project_name_with_owner,
  28. presence: true
  29. 1 validates :key,
  30. presence: true
  31. 1 validates :counter,
  32. presence: true
  33. 1 validates :activity_at,
  34. presence: true
  35. 1 scope :for_period, -> (start_date, end_date) {
  36. where(activity_at: (start_date..end_date))
  37. }
  38. 1 scope :for_users, -> (user_ids) {
  39. where(user_id: user_ids) if user_ids.present?
  40. }
  41. 1 scope :for_groups, -> (group_ids) {
  42. where(["project_id = ANY (
  43. ARRAY (
  44. SELECT target_id
  45. FROM relations
  46. INNER JOIN projects ON projects.id = relations.target_id
  47. WHERE relations.target_type = 'Project' AND
  48. projects.owner_type = 'Group' AND
  49. relations.actor_type = 'Group' AND
  50. relations.actor_id IN (:groups)
  51. )
  52. )", { groups: group_ids }
  53. ]) if group_ids.present?
  54. }
  55. 1 scope :build_lists_started, -> { where(key: KEY_BUILD_LIST_BUILD_STARTED) }
  56. 1 scope :build_lists_success, -> { where(key: KEY_BUILD_LIST_SUCCESS) }
  57. 1 scope :build_lists_error, -> { where(key: KEY_BUILD_LIST_BUILD_ERROR) }
  58. 1 scope :build_lists_published, -> { where(key: KEY_BUILD_LIST_BUILD_PUBLISHED) }
  59. 1 scope :commits, -> { where(key: KEY_COMMIT) }
  60. 1 scope :issues_open, -> { where(key: KEY_ISSUES_OPEN) }
  61. 1 scope :issues_reopen, -> { where(key: KEY_ISSUES_REOPEN) }
  62. 1 scope :issues_closed, -> { where(key: KEY_ISSUES_CLOSED) }
  63. 1 scope :pull_requests_open, -> { where(key: KEY_PULL_REQUESTS_OPEN) }
  64. 1 scope :pull_requests_merged, -> { where(key: KEY_PULL_REQUESTS_MERGED) }
  65. 1 scope :pull_requests_closed, -> { where(key: KEY_PULL_REQUESTS_CLOSED) }
  66. 1 def self.now_statsd_increment(activity_at: nil, user_id: nil, project_id: nil, key: nil, counter: 1)
  67. # Truncates a DateTime to the minute
  68. 3 activity_at = activity_at.utc.change(min: 0)
  69. 3 user = User.find user_id
  70. 3 project = Project.find project_id
  71. 3 Statistic.create(
  72. user_id: user_id,
  73. email: user.email,
  74. project_id: project_id,
  75. project_name_with_owner: project.name_with_owner,
  76. key: key,
  77. activity_at: activity_at
  78. )
  79. rescue ActiveRecord::RecordNotUnique
  80. # Do nothing, see: ensure
  81. ensure
  82. Statistic.where(
  83. user_id: user_id,
  84. project_id: project_id,
  85. key: key,
  86. activity_at: activity_at
  87. 3 ).update_all(['counter = counter + ?', counter]) if user_id.present? && project_id.present?
  88. end
  89. 1 def self.statsd_increment(options = {})
  90. 3 Statistic.perform_later(:middle, :now_statsd_increment, options)
  91. end
  92. end

app/models/subscribe.rb

43.24% lines covered

37 relevant lines. 16 lines covered and 21 lines missed.
    
  1. 1 class Subscribe < ActiveRecord::Base
  2. 1 belongs_to :user
  3. 1 belongs_to :project, optional: true
  4. 1 validates :user, presence: true
  5. 1 def subscribeable
  6. if commit_subscribe?
  7. project.repo.commit(Subscribe.hex_to_commit_hash commentable_id)
  8. else
  9. subscribeable_type.constantize.find_by_id(subscribeable_id)
  10. end
  11. end
  12. 1 def subscribeable=(c)
  13. if self.class.commit_subscribe?(c.class)
  14. self.subscribeable_id = c.id.hex
  15. else
  16. self.subscribeable_id = c.id
  17. end
  18. self.subscribeable_type = c.class.name
  19. end
  20. 1 def self.commit_subscribe?(class_name)
  21. class_name.to_s == 'Grit::Commit'
  22. end
  23. 1 def commit_subscribe?
  24. self.class.commit_subscribe?(subscribeable_type)
  25. end
  26. 1 def subscribed?
  27. status
  28. end
  29. 1 def self.comment_subscribes(comment)
  30. Subscribe.where(subscribeable_id: comment.commentable_id, subscribeable_type: comment.commentable.class.name, project_id: comment.project)
  31. end
  32. 1 def self.subscribed_to_commit?(project, user, commit)
  33. subscribe = user.subscribes.where(subscribeable_id: commit.id.hex, subscribeable_type: commit.class.name, project_id: project.id).first
  34. return subscribe.subscribed? if subscribe # return status if already subscribe present
  35. true
  36. end
  37. 1 def self.subscribe_to_commit(options)
  38. Subscribe.set_subscribe_to_commit(options, true)
  39. end
  40. 1 def self.unsubscribe_from_commit(options)
  41. Subscribe.set_subscribe_to_commit(options, false)
  42. end
  43. 1 def self.hex_to_commit_hash hex
  44. # '079d'.hex.to_s(16) => "79d"
  45. t = hex.to_s(16)
  46. '0'*(40-t.length) << t # commit hash has 40-character
  47. end
  48. 1 private
  49. 1 def self.set_subscribe_to_commit(options, status)
  50. if subscribe = Subscribe.where(options).first
  51. subscribe.update(status: status)
  52. else
  53. Subscribe.create options.merge(status: status)
  54. end
  55. end
  56. end

app/models/token.rb

83.33% lines covered

18 relevant lines. 15 lines covered and 3 lines missed.
    
  1. 1 class Token < ActiveRecord::Base
  2. 1 belongs_to :subject, polymorphic: true, touch: true
  3. 1 belongs_to :creator, class_name: 'User'
  4. 1 belongs_to :updater, class_name: 'User', optional: true
  5. 1 validates :creator_id, :subject_id, :subject_type, presence: true
  6. 1 validates :authentication_token, presence: true, uniqueness: { case_sensitive: true }
  7. 1 validates :description, length: { maximum: 1000 }
  8. 1 default_scope { order(created_at: :desc) }
  9. 1 scope :by_active, -> { where(status: 'active') }
  10. 1 before_validation :generate_token, on: :create
  11. 1 state_machine :status, initial: :active do
  12. 1 event :block do
  13. 1 transition [:active, :blocked] => :blocked
  14. end
  15. end
  16. 1 protected
  17. 1 def generate_token
  18. self.authentication_token = loop do
  19. token = SecureRandom.urlsafe_base64(32)
  20. break token unless Token.where(authentication_token: token).exists?
  21. end
  22. end
  23. end

app/models/user.rb

66.36% lines covered

107 relevant lines. 71 lines covered and 36 lines missed.
    
  1. 1 class User < Avatar
  2. 1 extend FriendlyId
  3. 1 friendly_id :uname, use: [:finders]
  4. 1 include PersonalRepository
  5. 1 include ActsLikeMember
  6. 1 include Feed::User
  7. 1 include EventLoggable
  8. 1 include TokenAuthenticatable
  9. 1 ROLES = ['', 'admin', 'banned', 'tester']
  10. 1 EXTENDED_ROLES = ROLES | ['system']
  11. 1 LANGUAGES_FOR_SELECT = [['Russian', 'ru'], ['English', 'en']]
  12. 1 LANGUAGES = LANGUAGES_FOR_SELECT.map(&:last)
  13. 1 NAME_REGEXP = /[a-z0-9_]+/
  14. 1 devise :database_authenticatable, :registerable, :recoverable,
  15. :rememberable, :validatable, :lockable, :confirmable
  16. 1 has_one :notifier, class_name: 'SettingsNotifier', dependent: :destroy #:notifier
  17. 1 has_one :builds_setting, class_name: 'UserBuildsSetting', dependent: :destroy
  18. 1 has_many :activity_feeds, dependent: :destroy
  19. 1 has_many :build_lists, dependent: :destroy
  20. 1 has_many :subscribes, foreign_key: :user_id, dependent: :destroy
  21. 1 has_many :comments, dependent: :destroy
  22. 1 has_many :relations, as: :actor, dependent: :destroy
  23. 1 has_many :targets, as: :actor, class_name: 'Relation', dependent: :destroy
  24. 1 has_many :projects, through: :targets, source: :target, source_type: 'Project', autosave: true
  25. 1 has_many :groups, through: :targets, source: :target, source_type: 'Group', autosave: true
  26. 1 has_many :platforms, through: :targets, source: :target, source_type: 'Platform', autosave: true
  27. 1 has_many :repositories, through: :targets, source: :target, source_type: 'Repository'
  28. 1 has_many :own_projects, as: :owner, class_name: 'Project', dependent: :destroy
  29. 1 has_many :own_groups, foreign_key: :owner_id, class_name: 'Group', dependent: :destroy
  30. 1 has_many :own_platforms, as: :owner, class_name: 'Platform', dependent: :destroy
  31. 1 has_many :issues
  32. 1 has_many :assigned_issues, foreign_key: :assignee_id, class_name: 'Issue', dependent: :nullify
  33. 1 has_many :key_pairs
  34. 1 has_many :ssh_keys, dependent: :destroy
  35. 1 has_many :invites, dependent: :destroy
  36. 1 has_one :invitation, class_name: 'Invite', foreign_key: :invited_user_id, dependent: :destroy
  37. 1 validates :uname, presence: true,
  38. uniqueness: { case_sensitive: false },
  39. format: { with: /\A#{NAME_REGEXP.source}\z/ },
  40. reserved_name: true,
  41. length: { maximum: 30 }
  42. 1 validates :name, length: { maximum: 100 }
  43. 13 validate { errors.add(:uname, :taken) if Group.by_uname(uname).present? }
  44. 1 validates :role, inclusion: { in: EXTENDED_ROLES }, allow_blank: true
  45. 1 validates :language, inclusion: { in: LANGUAGES }, allow_blank: true
  46. 1 attr_readonly :uname
  47. 1 attr_accessor :login, :delete_avatar, :invite_key
  48. 1 scope :opened, -> { where('users.role != \'system\' OR users.role IS NULL') }
  49. 1 scope :real, -> { where(role: ['', nil]) }
  50. 6 EXTENDED_ROLES.select { |type| type.present?}.each do |type|
  51. 4 scope type.to_sym, -> { where(role: type) }
  52. end
  53. 1 scope :member_of_project, ->(item) {
  54. where 'users.id IN (?)', item.members.map(&:id).uniq
  55. }
  56. 13 after_create -> { self.create_notifier unless self.system? }
  57. 1 before_create :ensure_authentication_token
  58. 1 def admin?
  59. role == 'admin'
  60. end
  61. 1 def user?
  62. persisted?
  63. end
  64. 1 def guest?
  65. 3 new_record?
  66. end
  67. 1 def tester?
  68. role == 'tester'
  69. end
  70. 1 def system?
  71. 24 role == 'system'
  72. end
  73. 1 def access_locked?
  74. 6 role == 'banned'
  75. end
  76. 1 def fullname
  77. return name.present? ? "#{uname} (#{name})" : uname
  78. end
  79. 1 def user_appeal
  80. 24 name.presence || uname
  81. end
  82. 1 class << self
  83. 1 def find_for_database_authentication(warden_conditions)
  84. conditions = warden_conditions.dup
  85. login = conditions.delete(:login)
  86. where(conditions)
  87. .where(["lower(uname) = :value OR lower(email) = :value OR authentication_token = :orig_value",
  88. { value: login.downcase, orig_value: login }]).first
  89. end
  90. 1 def auth_by_token_or_login_pass(user, pass)
  91. u = User.find_for_database_authentication(login: user)
  92. u if u && !u.access_locked? && (u.authentication_token == user || u.valid_password?(pass))
  93. end
  94. end
  95. # def update_with_password(params={})
  96. # params.delete(:current_password)
  97. # # self.update_without_password(params) # Don't allow password update
  98. # if params[:password].blank?
  99. # params.delete(:password)
  100. # params.delete(:password_confirmation) if params[:password_confirmation].blank?
  101. # end
  102. # result = update(params)
  103. # clean_up_passwords
  104. # result
  105. # end
  106. 1 def commentor?(commentable)
  107. comments.exists?(commentable_type: commentable.class.name, commentable_id: commentable.id.hex)
  108. end
  109. 1 def committer?(commit)
  110. email.downcase == commit.committer.email.downcase
  111. end
  112. 1 def owner_of? object
  113. if object.respond_to? :owner
  114. object.owner_id == self.id or self.group_ids.include? object.owner_id
  115. else
  116. false
  117. end
  118. end
  119. 1 def best_role target
  120. return nil if target.nil?
  121. roles = target_roles(target)
  122. return nil if roles.count == 0
  123. %w(admin writer reader).each {|role| return role if roles.include?(role)}
  124. raise "unknown user #{self.uname} roles #{roles}"
  125. end
  126. 1 def check_assigned_issues target
  127. if target.is_a? Project
  128. assigned_issues.where(project_id: target.id).update_all(assignee_id: nil)
  129. else
  130. project_ids = ProjectPolicy::Scope.new(self, Project).membered.distinct.pluck(:id)
  131. issues = assigned_issues
  132. issues = issues.where('project_id not in (?)', project_ids) if project_ids.present?
  133. issues.update_all(assignee_id: nil)
  134. end
  135. end
  136. 1 protected
  137. 1 def target_roles target
  138. rel, gr, roles = target.relations, self.groups, []
  139. if target.owner.class == Group
  140. owner_group = self.groups.where(id: target.owner.id).first
  141. roles += owner_group.actors.where(actor_id: self) if owner_group# user group is owner
  142. gr = gr.where('groups.id != ?', target.owner.id) # exclude target owner group from users group list
  143. end
  144. if target.class == Group
  145. roles += target.actors.where(actor_id: self.id, actor_type: 'User') # user is member of a target group
  146. else
  147. roles += rel.where(actor_id: gr.pluck(Arel.sql('DISTINCT groups.id')), actor_type: 'Group') # user group is member
  148. end
  149. roles += rel.where(actor_id: self.id, actor_type: 'User') # user is member
  150. roles.map(&:role).uniq
  151. end
  152. end

app/models/user_builds_setting.rb

100.0% lines covered

4 relevant lines. 4 lines covered and 0 lines missed.
    
  1. 1 class UserBuildsSetting < ActiveRecord::Base
  2. 1 include ExternalNodable
  3. 1 belongs_to :user
  4. 1 validates :user, presence: true
  5. end

app/models/wiki_page.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. 1 class WikiPage < Struct.new(:page, :format, :content, :footer, :sidebar)
  2. 1 include ActiveModel::Conversion
  3. 1 extend ActiveModel::Naming
  4. 1 attr_accessor :message, :rename
  5. 1 def rename
  6. @rename ||= page
  7. end
  8. end

app/policies/advisory_policy.rb

70.0% lines covered

10 relevant lines. 7 lines covered and 3 lines missed.
    
  1. 1 class AdvisoryPolicy < ApplicationPolicy
  2. 1 def index?
  3. true
  4. end
  5. 1 alias_method :search?, :index?
  6. 1 alias_method :show?, :index?
  7. 1 def create?
  8. !user.guest?
  9. end
  10. 1 alias_method :update?, :create?
  11. # Public: Get list of parameters that the user is allowed to alter.
  12. #
  13. # Returns Array
  14. 1 def permitted_attributes
  15. %i(
  16. description
  17. references
  18. )
  19. end
  20. end

app/policies/application_policy.rb

57.58% lines covered

66 relevant lines. 38 lines covered and 28 lines missed.
    
  1. 1 class ApplicationPolicy
  2. 1 attr_reader :user, :record
  3. 1 def initialize(user, record)
  4. # raise Pundit::NotAuthorizedError, 'must be logged in' unless user
  5. 9 @user = user || User.new
  6. 9 @record = record
  7. end
  8. 1 BASIC_ACTIONS = %i(index? show? create? update? destroy? destroy_all?)
  9. 1 def index?
  10. false
  11. end
  12. 1 def show?
  13. false
  14. end
  15. 1 def new?
  16. 1 create?
  17. end
  18. 1 def edit?
  19. update?
  20. end
  21. 1 def update?
  22. false
  23. end
  24. 1 def create?
  25. false
  26. end
  27. 1 def destroy?
  28. false
  29. end
  30. 1 def permitted_attributes
  31. []
  32. end
  33. 1 class Scope
  34. 1 attr_reader :user, :scope
  35. 1 def initialize(user, scope)
  36. @user = user
  37. @scope = scope
  38. end
  39. 1 def resolve
  40. scope
  41. end
  42. end
  43. # Public: Get user's group ids.
  44. #
  45. # Returns the Array of group ids.
  46. 1 def user_group_ids
  47. Rails.cache.fetch(['ApplicationPolicy#user_group_ids', user]) do
  48. user.group_ids
  49. end
  50. end
  51. 1 protected
  52. # Public: Check if provided user is the current user.
  53. #
  54. # Returns true if it is, false otherwise.
  55. 1 def current_user?(u)
  56. u == user
  57. end
  58. # Public: Check if provided user is guest.
  59. #
  60. # Returns true if he is, false otherwise.
  61. 1 def is_guest?
  62. user.new_record?
  63. end
  64. # Public: Check if provided user is user.
  65. #
  66. # Returns true if he is, false otherwise.
  67. 1 def is_user?
  68. user.persisted?
  69. end
  70. # Public: Check if provided user is tester.
  71. #
  72. # Returns true if he is, false otherwise.
  73. 1 def is_tester?
  74. user.role == 'tester'
  75. end
  76. # Public: Check if provided user is system.
  77. #
  78. # Returns true if he is, false otherwise.
  79. 1 def is_system?
  80. user.role == 'system'
  81. end
  82. # Public: Check if provided user is admin.
  83. #
  84. # Returns true if he is, false otherwise.
  85. 1 def is_admin?
  86. 6 user.role == 'admin'
  87. end
  88. # Public: Check if provided user is banned.
  89. #
  90. # Returns true if he is, false otherwise.
  91. 1 def is_banned?
  92. user.role == 'banned'
  93. end
  94. # Private: Check if provided user is at least record admin.
  95. #
  96. # Returns true if he is, false otherwise.
  97. 1 def local_admin?(r = record)
  98. owner?(r) || best_role(r) == 'admin'
  99. end
  100. # Private: Check if provided user is at least record reader.
  101. #
  102. # Returns true if he is, false otherwise.
  103. 1 def local_reader?(r = record)
  104. owner?(r) || %w(reader writer admin).include?(best_role(r))
  105. end
  106. # Private: Check if provided user is at least record writer.
  107. #
  108. # Returns true if he is, false otherwise.
  109. 1 def local_writer?(r = record)
  110. owner?(r) || %w(writer admin).include?(best_role(r))
  111. end
  112. # Private: Check if provided user is record owner.
  113. #
  114. # Returns true if he is, false otherwise.
  115. 1 def owner?(r = record)
  116. (
  117. 3 !r.try(:owner_type) && r.owner_id == user.id
  118. ) || (
  119. 3 r.try(:owner_type) == 'User' && r.owner_id == user.id
  120. ) || (
  121. r.try(:owner_type) == 'Group' && user_own_group_ids.include?(r.owner_id)
  122. )
  123. end
  124. # Private: Get the best role of user for record.
  125. #
  126. # Returns the String role or nil.
  127. 1 def best_role(r = record)
  128. Rails.cache.fetch(['ApplicationPolicy#best_role', r, user]) do
  129. user.best_role(r)
  130. end
  131. end
  132. # Public: Get own user's group ids.
  133. #
  134. # Returns the Array of own group ids.
  135. 1 def user_own_group_ids
  136. Rails.cache.fetch(['ApplicationPolicy#user_own_group_ids', user]) do
  137. user.own_group_ids
  138. end
  139. end
  140. # Public: Get user's platform ids.
  141. #
  142. # Returns the Array of platform ids.
  143. 1 def user_platform_ids
  144. Rails.cache.fetch(['ApplicationPolicy#user_platform_ids', user]) do
  145. user.repositories.pluck(:platform_id)
  146. end
  147. end
  148. end

app/policies/arch_policy.rb

66.67% lines covered

3 relevant lines. 2 lines covered and 1 lines missed.
    
  1. 1 class ArchPolicy < ApplicationPolicy
  2. 1 def index?
  3. true
  4. end
  5. end

app/policies/build_list_policy.rb

53.85% lines covered

52 relevant lines. 28 lines covered and 24 lines missed.
    
  1. 1 class BuildListPolicy < ApplicationPolicy
  2. 1 def index?
  3. true
  4. end
  5. 1 def show?
  6. record.user_id == user.id || ProjectPolicy.new(user, record.project).show?
  7. end
  8. 1 alias_method :read?, :show?
  9. 1 alias_method :log?, :show?
  10. 1 alias_method :everything?, :show?
  11. 1 alias_method :owned?, :show?
  12. 1 alias_method :everything?, :show?
  13. 1 alias_method :list?, :show?
  14. 1 def create?
  15. 3 return false unless record.project.is_package
  16. 3 return false unless ProjectPolicy.new(user, record.project).write?
  17. 3 record.build_for_platform.blank? || PlatformPolicy.new(user, record.build_for_platform).show?
  18. end
  19. 1 alias_method :rerun_tests?, :create?
  20. 1 def dependent_projects?
  21. record.save_to_platform.main? && create?
  22. end
  23. 1 def publish_into_testing?
  24. return false unless record.new_core?
  25. return false unless record.can_publish_into_testing?
  26. create? || ( record.save_to_platform.main? && publish? )
  27. end
  28. 1 def publish?
  29. return false unless record.new_core?
  30. return false unless record.can_publish?
  31. if record.build_published?
  32. local_admin?(record.save_to_platform) || record.save_to_repository.members.exists?(id: user.id)
  33. else
  34. record.save_to_repository.publish_without_qa ?
  35. ProjectPolicy.new(user, record.project).write? : local_admin?(record.save_to_platform)
  36. end
  37. end
  38. 1 alias_method :update_type?, :publish?
  39. 1 def create_container?
  40. return false unless record.new_core?
  41. ProjectPolicy.new(user, record.project).write? || local_admin?(record.save_to_platform)
  42. end
  43. 1 def reject_publish?
  44. record.save_to_repository.publish_without_qa ?
  45. ProjectPolicy.new(user, record.project).write? : local_admin?(record.save_to_platform)
  46. end
  47. 1 def cancel?
  48. ProjectPolicy.new(user, record.project).write?
  49. end
  50. # Public: Get list of parameters that the user is allowed to alter.
  51. #
  52. # Returns Array
  53. 1 def permitted_attributes
  54. pa = %i(
  55. arch_id
  56. auto_create_container
  57. auto_publish
  58. auto_publish_status
  59. build_for_platform_id
  60. commit_hash
  61. external_nodes
  62. include_testing_subrepository
  63. project_id
  64. project_version
  65. save_buildroot
  66. save_to_platform_id
  67. save_to_repository_id
  68. update_type
  69. use_cached_chroot
  70. use_extra_tests
  71. )
  72. pa << {
  73. include_repos: [],
  74. extra_build_lists: [],
  75. extra_repositories: [],
  76. extra_params: BuildList::EXTRA_PARAMS,
  77. }
  78. pa
  79. end
  80. 1 class Scope < Scope
  81. 1 def read
  82. scope.joins(:project).where <<-SQL, { user_id: policy.user.id, user_group_ids: policy.user_group_ids }
  83. (
  84. build_lists.user_id = :user_id
  85. ) OR (
  86. projects.visibility = 'open'
  87. ) OR (
  88. projects.owner_type = 'User' AND projects.owner_id = :user_id
  89. ) OR (
  90. projects.owner_type = 'Group' AND projects.owner_id IN (:user_group_ids)
  91. ) OR (
  92. projects.id = ANY (
  93. ARRAY (
  94. SELECT target_id
  95. FROM relations
  96. INNER JOIN projects ON projects.id = relations.target_id
  97. WHERE relations.target_type = 'Project' AND
  98. (
  99. projects.owner_type = 'User' AND projects.owner_id != :user_id OR
  100. projects.owner_type = 'Group' AND projects.owner_id NOT IN (:user_group_ids)
  101. ) AND (
  102. relations.actor_type = 'User' AND relations.actor_id = :user_id OR
  103. relations.actor_type = 'Group' AND relations.actor_id IN (:user_group_ids)
  104. )
  105. )
  106. )
  107. )
  108. SQL
  109. end
  110. 1 alias_method :everything, :read
  111. 1 def related
  112. scope.joins(:project).where <<-SQL, { user_id: policy.user.id, user_group_ids: policy.user_group_ids }
  113. (
  114. build_lists.user_id = :user_id
  115. ) OR (
  116. projects.owner_type = 'User' AND projects.owner_id = :user_id
  117. ) OR (
  118. projects.owner_type = 'Group' AND projects.owner_id IN (:user_group_ids)
  119. ) OR (
  120. projects.id = ANY (
  121. ARRAY (
  122. SELECT target_id
  123. FROM relations
  124. INNER JOIN projects ON projects.id = relations.target_id
  125. WHERE relations.target_type = 'Project' AND
  126. (
  127. projects.owner_type = 'User' AND projects.owner_id != :user_id OR
  128. projects.owner_type = 'Group' AND projects.owner_id NOT IN (:user_group_ids)
  129. ) AND (
  130. relations.actor_type = 'User' AND relations.actor_id = :user_id OR
  131. relations.actor_type = 'Group' AND relations.actor_id IN (:user_group_ids)
  132. )
  133. )
  134. )
  135. )
  136. SQL
  137. end
  138. 1 def owned
  139. scope.joins(:project).where(user_id: policy.user)
  140. end
  141. 1 def policy
  142. @policy ||= Pundit.policy!(user, :build_list)
  143. end
  144. end
  145. end

app/policies/collaborator_policy.rb

66.67% lines covered

3 relevant lines. 2 lines covered and 1 lines missed.
    
  1. 1 class CollaboratorPolicy < ApplicationPolicy
  2. # Public: Get list of parameters that the user is allowed to alter.
  3. #
  4. # Returns Array
  5. 1 def permitted_attributes
  6. %i(role actor_id actor_type)
  7. end
  8. end

app/policies/comment_policy.rb

60.0% lines covered

10 relevant lines. 6 lines covered and 4 lines missed.
    
  1. 1 class CommentPolicy < ApplicationPolicy
  2. 1 def create?
  3. !user.guest? && ProjectPolicy.new(user, record.project).show?
  4. end
  5. 1 alias_method :new_line?, :create?
  6. 1 def update?
  7. return false if user.guest?
  8. is_admin? || record.user_id == user.id || local_admin?(record.project)
  9. end
  10. 1 alias_method :destroy?, :update?
  11. # Public: Get list of parameters that the user is allowed to alter.
  12. #
  13. # Returns Array
  14. 1 def permitted_attributes
  15. %i(body data)
  16. end
  17. end

app/policies/group_policy.rb

65.52% lines covered

29 relevant lines. 19 lines covered and 10 lines missed.
    
  1. 1 class GroupPolicy < ApplicationPolicy
  2. 1 def index?
  3. !user.guest?
  4. end
  5. 1 alias_method :create?, :index?
  6. 1 alias_method :remove_user?, :index?
  7. 1 def show?
  8. true
  9. end
  10. 1 alias_method :projects?, :show?
  11. 1 def reader?
  12. !user.guest? && ( is_admin? || local_reader? )
  13. end
  14. 1 def write?
  15. !user.guest? && ( is_admin? || owner? || local_writer? )
  16. end
  17. 1 def update?
  18. !user.guest? && ( is_admin? || owner? || local_admin? )
  19. end
  20. 1 alias_method :add_member?, :update?
  21. 1 alias_method :manage_members?, :update?
  22. 1 alias_method :members?, :update?
  23. 1 alias_method :remove_member?, :update?
  24. 1 alias_method :remove_members?, :update?
  25. 1 alias_method :update_member?, :update?
  26. 1 def destroy?
  27. !user.guest? && ( is_admin? || owner? )
  28. end
  29. # Public: Get list of parameters that the user is allowed to alter.
  30. #
  31. # Returns Array
  32. 1 def permitted_attributes
  33. pa = %i(avatar description delete_avatar default_branch)
  34. pa << :uname if record.new_record?
  35. pa
  36. end
  37. 1 class Scope < Scope
  38. 1 def show
  39. scope
  40. end
  41. end
  42. end

app/policies/hook_policy.rb

77.78% lines covered

9 relevant lines. 7 lines covered and 2 lines missed.
    
  1. 1 class HookPolicy < ApplicationPolicy
  2. 1 def show?
  3. ProjectPolicy.new(user, record.project).update?
  4. end
  5. 1 alias_method :read?, :show?
  6. 1 alias_method :create?, :show?
  7. 1 alias_method :destroy?, :show?
  8. 1 alias_method :update?, :show?
  9. # Public: Get list of parameters that the user is allowed to alter.
  10. #
  11. # Returns Array
  12. 1 def permitted_attributes
  13. %i(data name)
  14. end
  15. end

app/policies/invite_policy.rb

60.0% lines covered

5 relevant lines. 3 lines covered and 2 lines missed.
    
  1. 1 class InvitePolicy < ApplicationPolicy
  2. 1 def invites?
  3. is_user?
  4. end
  5. 1 def create_invite?
  6. is_user?
  7. end
  8. end

app/policies/issue_policy.rb

36.84% lines covered

19 relevant lines. 7 lines covered and 12 lines missed.
    
  1. 1 class IssuePolicy < ApplicationPolicy
  2. 1 def index?
  3. # record.project.has_issues?
  4. true
  5. end
  6. 1 def show?
  7. return true if record.pull_request.present? # for redirect from a issue to a pull request
  8. return false unless record.project.has_issues?
  9. ProjectPolicy.new(user, record.project).show?
  10. end
  11. 1 alias_method :create?, :show?
  12. 1 alias_method :read?, :show?
  13. 1 def update?
  14. return false if user.guest?
  15. is_admin? || record.user_id == user.id || local_admin?(record.project)
  16. end
  17. # Public: Get list of parameters that the user is allowed to alter.
  18. #
  19. # Returns Array
  20. 1 def permitted_attributes
  21. pa = %i(title body)
  22. if ProjectPolicy.new(user, record.project).write?
  23. pa << :assignee_id
  24. pa << { labelings_attributes: %i(id name color label_id _destroy) }
  25. pa << { labelings: [] }
  26. end
  27. pa
  28. end
  29. end

app/policies/key_pair_policy.rb

57.14% lines covered

7 relevant lines. 4 lines covered and 3 lines missed.
    
  1. 1 class KeyPairPolicy < ApplicationPolicy
  2. 1 def create?
  3. return false unless record.repository
  4. is_admin? || local_admin?(record.repository.platform)
  5. end
  6. 1 alias_method :destroy?, :create?
  7. # Public: Get list of parameters that the user is allowed to alter.
  8. #
  9. # Returns Array
  10. 1 def permitted_attributes
  11. %i(public secret repository_id)
  12. end
  13. end

app/policies/mass_build_policy.rb

69.23% lines covered

13 relevant lines. 9 lines covered and 4 lines missed.
    
  1. 1 class MassBuildPolicy < ApplicationPolicy
  2. 1 def show?
  3. is_admin? || PlatformPolicy.new(user, record.save_to_platform).show?
  4. end
  5. 1 alias_method :read?, :show?
  6. 1 alias_method :get_list?, :show?
  7. 1 alias_method :show_fail_reason?, :show?
  8. 1 def create?
  9. is_admin? || owner?(record.save_to_platform) || local_admin?(record.save_to_platform)
  10. end
  11. 1 alias_method :publish?, :create?
  12. 1 def cancel?
  13. !record.stop_build && create?
  14. end
  15. # Public: Get list of parameters that the user is allowed to alter.
  16. #
  17. # Returns Array
  18. 1 def permitted_attributes
  19. %i(
  20. arches
  21. auto_create_container
  22. auto_publish_status
  23. build_for_platform_id
  24. description
  25. external_nodes
  26. include_testing_subrepository
  27. increase_release_tag
  28. projects_list
  29. repositories
  30. use_cached_chroot
  31. use_extra_tests
  32. ) << {
  33. extra_build_lists: [],
  34. extra_mass_builds: [],
  35. extra_repositories: []
  36. }
  37. end
  38. end

app/policies/platform_policy.rb

61.82% lines covered

55 relevant lines. 34 lines covered and 21 lines missed.
    
  1. 1 class PlatformPolicy < ApplicationPolicy
  2. 1 def index?
  3. !user.guest?
  4. end
  5. 1 def allowed?
  6. true
  7. end
  8. 1 alias_method :platforms_for_build?, :allowed?
  9. 1 def show?
  10. 2 return true if is_admin?
  11. 2 return true unless record.hidden?
  12. return true if record.owner == user
  13. owner? || local_reader? || user_platform_ids.include?(record.id)
  14. end
  15. 1 alias_method :projects?, :show?
  16. 1 alias_method :advisories?, :show?
  17. 1 alias_method :owned?, :show?
  18. 1 alias_method :read?, :show?
  19. 1 alias_method :related?, :show?
  20. 1 def members?
  21. return true if is_admin?
  22. return true unless record.hidden?
  23. return true if record.owner == user
  24. owner? || local_reader?
  25. end
  26. 1 def create?
  27. is_admin?
  28. end
  29. 1 def update?
  30. is_admin? || owner?
  31. end
  32. 1 alias_method :change_visibility?, :update?
  33. 1 def destroy?
  34. record.main? && ( is_admin? || owner? )
  35. end
  36. 1 def local_admin_manage?
  37. is_admin? || owner? || local_admin?
  38. end
  39. 1 alias_method :add_project?, :local_admin_manage?
  40. 1 alias_method :remove_file?, :local_admin_manage?
  41. 1 def clone?
  42. record.main? && is_admin?
  43. end
  44. 1 alias_method :make_clone?, :clone?
  45. 1 def add_member?
  46. record.main? && ( is_admin? || owner? || local_admin? )
  47. end
  48. 1 alias_method :regenerate_metadata?, :add_member?
  49. 1 alias_method :remove_member?, :add_member?
  50. 1 alias_method :remove_members?, :add_member?
  51. 1 def clear?
  52. record.personal? && ( is_admin? || owner? )
  53. end
  54. # Public: Get list of parameters that the user is allowed to alter.
  55. #
  56. # Returns Array
  57. 1 def permitted_attributes
  58. %i(
  59. admin_id
  60. automatic_metadata_regeneration
  61. default_branch
  62. description
  63. distrib_type
  64. name
  65. owner
  66. parent_platform_id
  67. platform_type
  68. released
  69. term
  70. visibility
  71. ) + [
  72. platform_arch_settings_attributes: %i(id arch_id platform_id default time_living)
  73. ]
  74. end
  75. 1 class Scope < Scope
  76. 1 def related
  77. scope.where <<-SQL, { user_id: policy.user.id, user_group_ids: policy.user_group_ids, platform_ids: related_platform_ids }
  78. (
  79. platforms.id IN (:platform_ids)
  80. ) OR (
  81. platforms.owner_type = 'User' AND platforms.owner_id = :user_id
  82. ) OR (
  83. platforms.owner_type = 'Group' AND platforms.owner_id IN (:user_group_ids)
  84. ) OR (
  85. platforms.id = ANY (
  86. ARRAY (
  87. SELECT target_id
  88. FROM relations
  89. INNER JOIN platforms ON platforms.id = relations.target_id
  90. WHERE relations.target_type = 'Platform' AND
  91. (
  92. platforms.owner_type = 'User' AND platforms.owner_id != :user_id
  93. ) AND (
  94. relations.actor_type = 'User' AND relations.actor_id = :user_id
  95. )
  96. )
  97. )
  98. )
  99. SQL
  100. end
  101. 1 def show
  102. scope.where <<-SQL, { user_id: policy.user.id, user_group_ids: policy.user_group_ids, platform_ids: related_platform_ids, visibility: Platform::VISIBILITY_OPEN }
  103. (
  104. platforms.visibility = :visibility
  105. ) OR (
  106. platforms.id IN (:platform_ids)
  107. ) OR (
  108. platforms.owner_type = 'User' AND platforms.owner_id = :user_id
  109. ) OR (
  110. platforms.owner_type = 'Group' AND platforms.owner_id IN (:user_group_ids)
  111. ) OR (
  112. platforms.id = ANY (
  113. ARRAY (
  114. SELECT target_id
  115. FROM relations
  116. INNER JOIN platforms ON platforms.id = relations.target_id
  117. WHERE relations.target_type = 'Platform' AND
  118. (
  119. platforms.owner_type = 'User' AND platforms.owner_id != :user_id
  120. ) AND (
  121. relations.actor_type = 'User' AND relations.actor_id = :user_id
  122. )
  123. )
  124. )
  125. )
  126. SQL
  127. end
  128. 1 protected
  129. 1 def policy
  130. @policy ||= Pundit.policy!(user, :platform)
  131. end
  132. 1 def related_platform_ids
  133. Rails.cache.fetch(['PlatformPolicy::Scope#related_platform_ids', policy.user]) do
  134. policy.user.repositories.pluck(:platform_id)
  135. end
  136. end
  137. end
  138. end

app/policies/product_build_list_policy.rb

58.82% lines covered

17 relevant lines. 10 lines covered and 7 lines missed.
    
  1. 1 class ProductBuildListPolicy < ApplicationPolicy
  2. 1 def index?
  3. true
  4. end
  5. 1 def show?
  6. is_admin? || ProductPolicy.new(user, record.product).show?
  7. end
  8. 1 alias_method :log?, :show?
  9. 1 alias_method :read?, :show?
  10. 1 def create?
  11. return false unless record.project && record.product
  12. is_admin? || ProjectPolicy.new(user, record.project).write? || ProductPolicy.new(user, record.product).update?
  13. end
  14. 1 alias_method :cancel?, :create?
  15. 1 def update?
  16. is_admin? || ProductPolicy.new(user, record.product).update?
  17. end
  18. 1 def destroy?
  19. is_admin? || ProductPolicy.new(user, record.product).destroy?
  20. end
  21. # Public: Get list of parameters that the user is allowed to alter.
  22. #
  23. # Returns Array
  24. 1 def permitted_attributes
  25. %i(
  26. base_url
  27. branch
  28. commit_hash
  29. main_script
  30. not_delete
  31. params
  32. product_id
  33. product_name
  34. project_id
  35. project_version
  36. status
  37. time_living
  38. )
  39. end
  40. end

app/policies/product_policy.rb

64.29% lines covered

14 relevant lines. 9 lines covered and 5 lines missed.
    
  1. 1 class ProductPolicy < ApplicationPolicy
  2. 1 def index?
  3. record.platform.main?
  4. end
  5. 1 def show?
  6. is_admin? || PlatformPolicy.new(user, record.platform).show?
  7. end
  8. 1 alias_method :read?, :show?
  9. 1 def create?
  10. return false unless record.platform
  11. is_admin? || record.platform.main? && ( owner?(record.platform) || local_admin?(record.platform) )
  12. end
  13. 1 alias_method :clone?, :create?
  14. 1 alias_method :destroy?, :create?
  15. 1 alias_method :update?, :create?
  16. # Public: Get list of parameters that the user is allowed to alter.
  17. #
  18. # Returns Array
  19. 1 def permitted_attributes
  20. %i(
  21. autostart_status
  22. description
  23. main_script
  24. name
  25. params
  26. platform_id
  27. project_id
  28. project_version
  29. time_living
  30. )
  31. end
  32. end

app/policies/project_policy.rb

61.76% lines covered

68 relevant lines. 42 lines covered and 26 lines missed.
    
  1. 1 class ProjectPolicy < ApplicationPolicy
  2. 1 def index?
  3. !user.guest?
  4. end
  5. 1 alias_method :autocomplete_project?, :index?
  6. 1 alias_method :remove_user?, :index?
  7. 1 alias_method :preview?, :index?
  8. 1 def show?
  9. 1 return true if is_admin?
  10. 1 return true if record.public?
  11. return true if record.owner == user
  12. return true if record.owner.is_a?(Group) && user_group_ids.include?(record.owner_id)
  13. local_reader?
  14. end
  15. 1 alias_method :read?, :show?
  16. 1 alias_method :archive?, :show?
  17. 1 alias_method :get_sha1_of_archive?, :show?
  18. 1 alias_method :get_id?, :show?
  19. 1 alias_method :refs_list?, :show?
  20. 1 def fork?
  21. !user.guest? && show?
  22. end
  23. 1 def create?
  24. return false if user.guest?
  25. return true if is_admin?
  26. record.is_a?(Symbol) || owner_policy.write?
  27. end
  28. 1 def update?
  29. return false if user.guest?
  30. is_admin? || owner? || local_admin?
  31. end
  32. 1 alias_method :add_member?, :update?
  33. 1 alias_method :alias?, :update?
  34. 1 alias_method :autocomplete_maintainers?, :update?
  35. 1 alias_method :manage_collaborators?, :update?
  36. 1 alias_method :members?, :update?
  37. 1 alias_method :remove_member?, :update?
  38. 1 alias_method :remove_members?, :update?
  39. 1 alias_method :schedule?, :update?
  40. 1 alias_method :sections?, :update?
  41. 1 alias_method :update_member?, :update?
  42. 1 def destroy?
  43. return false if user.guest?
  44. is_admin? || owner? || record.owner.is_a?(Group) && record.owner.actors.exists?(actor_type: 'User', actor_id: user.id, role: 'admin')
  45. end
  46. 1 def mass_import?
  47. return false if user.guest?
  48. is_admin? || user.platforms.main.find{ |p| local_admin?(p) }.present?
  49. end
  50. 1 def run_mass_import?
  51. return true if is_admin?
  52. return false unless owner_policy.write?
  53. repo = Repository.find(record.add_to_repository_id)
  54. repo.platform.main? && PlatformPolicy.new(user, repo.platform).add_project?
  55. end
  56. # for grack
  57. 1 def write?
  58. 3 return false if user.guest?
  59. 3 is_admin? || owner? || local_writer?
  60. end
  61. 1 def possible_forks?
  62. true
  63. end
  64. # Public: Get list of parameters that the user is allowed to alter.
  65. #
  66. # Returns Array
  67. 1 def permitted_attributes
  68. %i(
  69. add_to_repository_id
  70. architecture_dependent
  71. autostart_status
  72. default_branch
  73. description
  74. has_issues
  75. has_wiki
  76. is_package
  77. maintainer_id
  78. mass_import
  79. name
  80. publish_i686_into_x86_64
  81. srpm
  82. srpms_list
  83. url
  84. visibility
  85. )
  86. end
  87. 1 class Scope < Scope
  88. 1 def membered
  89. scope.where <<-SQL, { user_id: policy.user.id, user_group_ids: policy.user_group_ids }
  90. (
  91. projects.owner_type = 'User' AND projects.owner_id = :user_id
  92. ) OR (
  93. projects.owner_type = 'Group' AND projects.owner_id IN (:user_group_ids)
  94. ) OR (
  95. projects.id = ANY (
  96. ARRAY (
  97. SELECT target_id
  98. FROM relations
  99. INNER JOIN projects ON projects.id = relations.target_id
  100. WHERE relations.target_type = 'Project' AND
  101. (
  102. projects.owner_type = 'User' AND projects.owner_id != :user_id OR
  103. projects.owner_type = 'Group' AND projects.owner_id NOT IN (:user_group_ids)
  104. ) AND (
  105. relations.actor_type = 'User' AND relations.actor_id = :user_id OR
  106. relations.actor_type = 'Group' AND relations.actor_id IN (:user_group_ids)
  107. )
  108. )
  109. )
  110. )
  111. SQL
  112. end
  113. 1 def read
  114. scope.where <<-SQL, { user_id: policy.user.id, user_group_ids: policy.user_group_ids }
  115. (
  116. projects.visibility = 'open'
  117. ) OR (
  118. projects.owner_type = 'User' AND projects.owner_id = :user_id
  119. ) OR (
  120. projects.owner_type = 'Group' AND projects.owner_id IN (:user_group_ids)
  121. ) OR (
  122. projects.id = ANY (
  123. ARRAY (
  124. SELECT target_id
  125. FROM relations
  126. INNER JOIN projects ON projects.id = relations.target_id
  127. WHERE relations.target_type = 'Project' AND
  128. (
  129. projects.owner_type = 'User' AND projects.owner_id != :user_id OR
  130. projects.owner_type = 'Group' AND projects.owner_id NOT IN (:user_group_ids)
  131. ) AND (
  132. relations.actor_type = 'User' AND relations.actor_id = :user_id OR
  133. relations.actor_type = 'Group' AND relations.actor_id IN (:user_group_ids)
  134. )
  135. )
  136. )
  137. )
  138. SQL
  139. end
  140. 1 alias_method :show, :read
  141. 1 protected
  142. 1 def policy
  143. @policy ||= Pundit.policy!(user, :project)
  144. end
  145. end
  146. 1 private
  147. 1 def owner_policy
  148. if record.owner.is_a?(User)
  149. UserPolicy.new(user, record.owner)
  150. else
  151. GroupPolicy.new(user, record.owner)
  152. end
  153. end
  154. end

app/policies/pull_request_policy.rb

58.82% lines covered

17 relevant lines. 10 lines covered and 7 lines missed.
    
  1. 1 class PullRequestPolicy < ApplicationPolicy
  2. 1 def index?
  3. true
  4. end
  5. 1 def show?
  6. is_admin? || ProjectPolicy.new(user, record.to_project).show?
  7. end
  8. 1 alias_method :read?, :show?
  9. 1 alias_method :commits?, :show?
  10. 1 alias_method :files?, :show?
  11. 1 alias_method :create?, :show?
  12. 1 def update?
  13. return false if user.guest?
  14. is_admin? || record.user_id == user.id || local_writer?(record.to_project)
  15. end
  16. 1 def merge?
  17. return false if user.guest?
  18. is_admin? || local_writer?(record.to_project)
  19. end
  20. # Public: Get list of parameters that the user is allowed to alter.
  21. #
  22. # Returns Array
  23. 1 def permitted_attributes
  24. %i(
  25. body
  26. from_ref
  27. title
  28. to_ref
  29. ) + [ issue_attributes: %i(title body) ]
  30. end
  31. end

app/policies/repository_policy.rb

66.67% lines covered

42 relevant lines. 28 lines covered and 14 lines missed.
    
  1. 1 class RepositoryPolicy < ApplicationPolicy
  2. 1 def show?
  3. is_admin? || PlatformPolicy.new(user, record.platform).show?
  4. end
  5. 1 alias_method :projects?, :show?
  6. 1 alias_method :projects_list?, :show?
  7. 1 alias_method :read?, :show?
  8. 1 alias_method :public_key?, :show?
  9. 1 def reader?
  10. is_admin? || local_reader?(record.platform)
  11. end
  12. 1 def write?
  13. is_admin? || local_writer?(record.platform)
  14. end
  15. 1 def update?
  16. is_admin? || local_admin?(record.platform)
  17. end
  18. 1 alias_method :manage_members?, :update?
  19. 1 alias_method :regenerate_metadata?, :update?
  20. 1 alias_method :signatures?, :update?
  21. 1 def create?
  22. return false if record.platform.personal? && record.name == 'main'
  23. is_admin? || owner?(record.platform) || local_admin?(record.platform)
  24. end
  25. 1 alias_method :destroy?, :create?
  26. 1 def packages?
  27. record.platform.main? && ( is_admin? || local_admin?(record.platform) )
  28. end
  29. 1 alias_method :remove_member?, :packages?
  30. 1 alias_method :remove_members?, :packages?
  31. 1 alias_method :add_member?, :packages?
  32. 1 alias_method :sync_lock_file?, :packages?
  33. 1 def add_project?
  34. is_admin? || local_admin?(record.platform) || repository_user_ids.include?(user.id)
  35. end
  36. 1 alias_method :remove_project?, :add_project?
  37. 1 def settings?
  38. is_admin? || owner?(record.platform) || local_admin?(record.platform)
  39. end
  40. 1 def key_pair?
  41. user.system?
  42. end
  43. 1 def add_repo_lock_file?
  44. is_admin? || user.system? || ( record.platform.main? && local_admin?(record.platform) )
  45. end
  46. 1 alias_method :remove_repo_lock_file?, :add_repo_lock_file?
  47. # Public: Get list of parameters that the user is allowed to alter.
  48. #
  49. # Returns Array
  50. 1 def permitted_attributes
  51. %i(
  52. name
  53. description
  54. publish_without_qa
  55. synchronizing_publications
  56. publish_builds_only_from_branch
  57. build_for_platform_id
  58. resign_rpms
  59. )
  60. end
  61. 1 private
  62. # Public: Get user ids of repository.
  63. #
  64. # Returns the Set of user ids.
  65. 1 def repository_user_ids
  66. Rails.cache.fetch(['RepositoryPolicy#repository_user_ids', record]) do
  67. Set.new record.member_ids
  68. end
  69. end
  70. end

app/policies/search_policy.rb

66.67% lines covered

3 relevant lines. 2 lines covered and 1 lines missed.
    
  1. 1 class SearchPolicy < ApplicationPolicy
  2. 1 def index?
  3. APP_CONFIG['anonymous_access'] || !user.guest?
  4. end
  5. end

app/policies/settings_notifier_policy.rb

66.67% lines covered

3 relevant lines. 2 lines covered and 1 lines missed.
    
  1. 1 class SettingsNotifierPolicy < ApplicationPolicy
  2. # Public: Get list of parameters that the user is allowed to alter.
  3. #
  4. # Returns Array
  5. 1 def permitted_attributes
  6. %i(
  7. can_notify
  8. update_code
  9. new_comment_commit_owner
  10. new_comment_commit_repo_owner
  11. new_comment_commit_commentor
  12. new_comment
  13. new_comment_reply
  14. new_issue
  15. issue_assign
  16. new_build
  17. new_associated_build
  18. )
  19. end
  20. end

app/policies/ssh_key_policy.rb

66.67% lines covered

3 relevant lines. 2 lines covered and 1 lines missed.
    
  1. 1 class SshKeyPolicy < ApplicationPolicy
  2. # Public: Get list of parameters that the user is allowed to alter.
  3. #
  4. # Returns Array
  5. 1 def permitted_attributes
  6. %i(key name)
  7. end
  8. end

app/policies/statistic_policy.rb

66.67% lines covered

3 relevant lines. 2 lines covered and 1 lines missed.
    
  1. 1 class StatisticPolicy < ApplicationPolicy
  2. 1 def index?
  3. true
  4. end
  5. end

app/policies/subscribe_policy.rb

36.36% lines covered

11 relevant lines. 4 lines covered and 7 lines missed.
    
  1. 1 class SubscribePolicy < ApplicationPolicy
  2. 1 def create?
  3. return false if user.guest?
  4. return true if record.subscribeable.is_a?(Grit::Commit)
  5. !record.subscribeable.subscribes.exists?(user_id: user.id)
  6. end
  7. 1 def destroy?
  8. return false if user.guest?
  9. return true if record.subscribeable.is_a?(Grit::Commit)
  10. record.subscribeable.subscribes.exists?(user_id: user.id)
  11. end
  12. # Public: Get list of parameters that the user is allowed to alter.
  13. #
  14. # Returns Array
  15. 1 def permitted_attributes
  16. %i(status user_id)
  17. end
  18. end

app/policies/token_policy.rb

75.0% lines covered

8 relevant lines. 6 lines covered and 2 lines missed.
    
  1. 1 class TokenPolicy < ApplicationPolicy
  2. 1 def show?
  3. # local_admin?(record.subject)
  4. is_admin? || owner?(record.subject) || local_admin?(record.subject)
  5. end
  6. 1 alias_method :create?, :show?
  7. 1 alias_method :read?, :show?
  8. 1 alias_method :withdraw?, :show?
  9. # Public: Get list of parameters that the user is allowed to alter.
  10. #
  11. # Returns Array
  12. 1 def permitted_attributes
  13. %i(description)
  14. end
  15. end

app/policies/user_builds_setting_policy.rb

66.67% lines covered

3 relevant lines. 2 lines covered and 1 lines missed.
    
  1. 1 class UserBuildsSettingPolicy < ApplicationPolicy
  2. # Public: Get list of parameters that the user is allowed to alter.
  3. #
  4. # Returns Array
  5. 1 def permitted_attributes
  6. %i(external_nodes) + [platforms: []]
  7. end
  8. end

app/policies/user_policy.rb

66.67% lines covered

15 relevant lines. 10 lines covered and 5 lines missed.
    
  1. 1 class UserPolicy < ApplicationPolicy
  2. 1 def show?
  3. true
  4. end
  5. 1 def update?
  6. is_admin? || record == user
  7. end
  8. 1 alias_method :notifiers?, :update?
  9. 1 alias_method :show_current_user?, :update?
  10. 1 alias_method :write?, :update?
  11. 1 def tokens?
  12. user.role == 'system'
  13. end
  14. # Public: Get list of parameters that the user is allowed to alter.
  15. #
  16. # Returns Array
  17. 1 def permitted_attributes
  18. %i(
  19. avatar
  20. company
  21. current_password
  22. delete_avatar
  23. email
  24. hide_email
  25. language
  26. location
  27. login
  28. name
  29. password
  30. password_confirmation
  31. professional_experience
  32. remember_me
  33. site
  34. sound_notifications
  35. uname
  36. )
  37. end
  38. 1 class Scope < Scope
  39. 1 def show
  40. scope
  41. end
  42. end
  43. end

app/presenters/abf_worker_status_presenter.rb

21.88% lines covered

32 relevant lines. 7 lines covered and 25 lines missed.
    
  1. 1 class AbfWorkerStatusPresenter < ApplicationPresenter
  2. 1 def initialize
  3. end
  4. 1 def projects_status
  5. Rails.cache.fetch([AbfWorkerStatusPresenter, :projects_status], expires_in: 10.seconds) do
  6. result = get_status(:rpm, :publish) { |w, worker| w.to_s =~ /#{worker}_worker_default/ }
  7. nodes = RpmBuildNode.total_statistics
  8. result[:rpm][:workers] += nodes[:systems]
  9. result[:rpm][:build_tasks] += nodes[:busy]
  10. result[:rpm][:other_workers] = nodes[:others]
  11. external_bls = BuildList.for_status(BuildList::BUILD_PENDING).where(mass_build_id: nil).count
  12. result[:rpm][:default_tasks] = external_bls
  13. mass_build_tasks = BuildList.for_status(BuildList::BUILD_PENDING).where.not(mass_build_id: nil).count
  14. result[:rpm][:low_tasks] = mass_build_tasks
  15. result[:rpm][:tasks] += external_bls + mass_build_tasks
  16. result
  17. end
  18. end
  19. 1 def products_status
  20. get_status(:iso) { |w, worker|
  21. str = w.to_s
  22. str =~ /iso_worker/ && str !~ /observer/
  23. }
  24. end
  25. 1 protected
  26. 1 def get_status(*queues)
  27. status = {}
  28. queues.each do |worker|
  29. workers = Resque.workers.select{ |w| yield w, worker }
  30. status[worker] = status_of_worker workers, worker
  31. end
  32. status
  33. end
  34. 1 def status_of_worker(workers, worker)
  35. key = "resque:queue:#{worker}_worker"
  36. default_tasks, tasks = Redis.current.llen("#{key}_default"), Redis.current.llen(key)
  37. {
  38. workers: workers.count,
  39. build_tasks: workers.select{ |w| w.working? }.count,
  40. default_tasks: default_tasks,
  41. low_tasks: tasks,
  42. tasks: (default_tasks + tasks)
  43. }
  44. end
  45. end

app/presenters/api/v1/repository_package_presenter.rb

47.06% lines covered

17 relevant lines. 8 lines covered and 9 lines missed.
    
  1. 1 require 'csv'
  2. 1 class Api::V1::RepositoryPackagePresenter < ApplicationPresenter
  3. CSV_HEADERS = {
  4. 1 project_owner: 'Project owner',
  5. project_name: 'Project name',
  6. package_name: 'Package name',
  7. epoch: 'Epoch',
  8. version: 'Version',
  9. release: 'Release',
  10. maintainer_uname: 'Maintainer uname',
  11. maintainer_email: 'Maintainer email',
  12. committer_uname: 'Committer uname',
  13. committer_email: 'Committer email'
  14. }
  15. 1 attr_reader :package
  16. 1 delegate *%i(project name epoch version release assignee build_list), to: :package
  17. 1 def initialize(package)
  18. @package = package
  19. end
  20. 1 def to_csv_row
  21. commit = project.repo.commit(build_list.commit_hash)
  22. committer = User.where(email: commit.committer.email).first || commit.committer if commit
  23. if committer.is_a? User
  24. committer_uname, committer_email = committer.uname, committer.email
  25. elsif committer.is_a? Grit::Actor
  26. committer_uname, committer_email = committer.name, committer.email
  27. end
  28. CSV::Row.new(
  29. CSV_HEADERS.keys,
  30. [
  31. project.owner_uname,
  32. project.name,
  33. name,
  34. epoch,
  35. version,
  36. release,
  37. assignee.uname,
  38. assignee.email,
  39. committer_uname,
  40. committer_email
  41. ]
  42. )
  43. end
  44. 1 def self.csv_header
  45. # Using ruby's built-in CSV::Row class
  46. # true - means its a header
  47. CSV::Row.new CSV_HEADERS.keys, CSV_HEADERS.values, true
  48. end
  49. end

app/presenters/application_presenter.rb

100.0% lines covered

1 relevant lines. 1 lines covered and 0 lines missed.
    
  1. 1 class ApplicationPresenter < RosaPresenter::Base
  2. end
  3. #class ApplicationPresenter
  4. # include ActionDispatch::Routing::UrlFor
  5. # include ActionView::Helpers::UrlHelper
  6. # include Rails.application.routes.url_helpers
  7. #
  8. # attr_accessor :controller
  9. #
  10. # def initialize(item, opts)
  11. # end
  12. #
  13. # # TODO it needs to be refactored!
  14. # class << self
  15. # def present(item, opts, &block)
  16. # block.call(self.new(item, opts))
  17. # end
  18. #
  19. # def present_collection(collection, &block)
  20. # res = collection.map {|e| self.new(*e)}
  21. # if block.present?
  22. # res = res.inject('') do |akk, presenter|
  23. # akk << block.call(presenter)
  24. # akk
  25. # end
  26. # end
  27. # return res
  28. # end
  29. # end
  30. #
  31. # protected
  32. #
  33. # def t(*args)
  34. # I18n.translate(*args)
  35. # end
  36. #
  37. # def l(*args)
  38. # I18n.localize(*args)
  39. # end
  40. #end
  41. #
  42. #module Presenters
  43. # module Activation
  44. # def self.included(klass) # :nodoc:
  45. # klass.prepend_before_filter :activate_presenter
  46. # end
  47. #
  48. # private
  49. # def activate_presenter
  50. # ApplicationPresenter.controller = self
  51. # end
  52. # end
  53. #end
  54. #ActionController::Base.send(:include, Presenters::Activation)

app/presenters/comment_presenter.rb

27.27% lines covered

66 relevant lines. 18 lines covered and 48 lines missed.
    
  1. 1 class CommentPresenter < ApplicationPresenter
  2. 1 include PullRequestHelper
  3. 1 attr_accessor :comment, :options
  4. 1 attr_reader :header, :image, :date, :caption, :content, :buttons, :is_reference_to_issue,
  5. :reference_project
  6. 1 def initialize(comment, opts = {})
  7. @is_reference_to_issue = !!(comment.automatic && comment.created_from_issue_id) # is it reference issue from another issue
  8. @comment, @user, @options = comment, comment.user, opts
  9. unless @is_reference_to_issue
  10. @content = @comment.body
  11. else
  12. issue = Issue.where(id: comment.created_from_issue_id).first
  13. if issue && (comment.data[:comment_id].nil? || Comment.exists?(comment.data[:comment_id]))
  14. @referenced_issue = issue.pull_request || issue
  15. @reference_project = issue.project
  16. title = if issue == opts[:commentable]
  17. "#{issue.serial_id}"
  18. elsif issue.project.owner == opts[:commentable].project.owner
  19. "#{issue.project.name}##{issue.serial_id}"
  20. else
  21. "#{issue.project.name_with_owner}##{issue.serial_id}"
  22. end
  23. title = "<span style=\"color: #777;\">#{title}</span>:"
  24. issue_link = project_issue_path(issue.project, issue)
  25. @content = "<a href=\"#{issue_link}\">#{title} #{issue.title}</a>".html_safe
  26. else
  27. @content = t 'layout.comments.removed'
  28. end
  29. end
  30. end
  31. 1 def expandable?
  32. false
  33. end
  34. 1 def buttons?
  35. !@is_reference_to_issue # dont show for automatic comment
  36. end
  37. 1 def content?
  38. true
  39. end
  40. 1 def caption?
  41. false
  42. end
  43. 1 def issue_referenced_state?
  44. @referenced_issue # show state of the existing referenced issue
  45. end
  46. 1 def buttons
  47. project, commentable = options[:project], options[:commentable]
  48. link_to_comment = "#{helpers.project_commentable_path(project, commentable)}##{comment_anchor}"
  49. klass = "#{@options[:in_discussion].present? ? 'in_discussion_' : ''}link_to_comment"
  50. res = [ link_to(content_tag(:i, nil, class: 'fa fa-link'),
  51. link_to_comment,
  52. class: klass).html_safe ]
  53. if controller.policy(@comment).update?
  54. res << link_to(content_tag(:i, nil, class: 'fa fa-edit'),
  55. "#update-comment#{comment.id}",
  56. 'ng-click' => "commentsCtrl.toggleEditForm(#{comment_id})" ).html_safe
  57. end
  58. if controller.policy(@comment).destroy?
  59. res << link_to(content_tag(:i, nil, class: 'fa fa-close'),
  60. '',
  61. 'ng-click' => "commentsCtrl.remove(#{comment_id})").html_safe
  62. end
  63. res
  64. end
  65. 1 def header
  66. user_link = link_to @user.fullname, user_path(@user.uname)
  67. res = unless @is_reference_to_issue
  68. "#{user_link} #{t 'layout.comments.has_commented'}"
  69. else
  70. t 'layout.comments.reference', user: user_link
  71. end
  72. res.html_safe
  73. end
  74. 1 def image
  75. @image ||= helpers.avatar_url(@user, :medium)
  76. end
  77. 1 def date
  78. @date ||= @comment.created_at
  79. end
  80. 1 def comment_id?
  81. true
  82. end
  83. 1 def comment_id
  84. @comment.id
  85. end
  86. 1 def comment_anchor
  87. # check for pull diff inline comment
  88. before = if @options[:add_anchor].present? && !@options[:in_discussion]
  89. 'diff-'
  90. else
  91. ''
  92. end
  93. "#{before}comment#{@comment.id}"
  94. end
  95. 1 def issue_referenced_state
  96. if @referenced_issue.is_a? Issue
  97. statuses = {'open' => 'success', 'closed' => 'danger'}
  98. content_tag :span, t("layout.issues.status.#{@referenced_issue.status}"), class: "pull-right label label-#{statuses[@referenced_issue.status]}"
  99. else
  100. pull_status_label @referenced_issue.status, class: 'pull-right'
  101. end.html_safe
  102. end
  103. end

app/presenters/git_presenters/commit_as_message_presenter.rb

28.79% lines covered

66 relevant lines. 19 lines covered and 47 lines missed.
    
  1. 1 class GitPresenters::CommitAsMessagePresenter < ApplicationPresenter
  2. 1 include CommitHelper
  3. 1 attr_accessor :commit
  4. 1 attr_reader :header, :image, :date, :caption, :content, :expandable,
  5. :is_reference_to_issue, :committer
  6. 1 def initialize(commit, opts = {})
  7. comment = opts[:comment]
  8. @is_reference_to_issue = !!comment # is it reference issue from commit
  9. @project = if comment
  10. Project.where(id: comment.data[:from_project_id]).first
  11. else
  12. opts[:project]
  13. end
  14. commit = commit || @project.repo.commit(Comment.hex_to_commit_hash comment.created_from_commit_hash) if @project
  15. if @project && commit
  16. @committer = User.where(email: commit.committer.email).first || commit.committer
  17. @commit_hash = commit.id
  18. @committed_date, @authored_date = commit.committed_date, commit.authored_date
  19. @commit_message = commit.message
  20. else
  21. @committer = t('layout.commits.unknown_committer')
  22. @commit_hash = Comment.hex_to_commit_hash comment.created_from_commit_hash
  23. @committed_date = @authored_date = comment.created_at
  24. @commit_message = t('layout.commits.deleted')
  25. end
  26. prepare_message
  27. end
  28. 1 def header
  29. @header ||= if @is_reference_to_issue
  30. I18n.t('layout.commits.reference', committer: committer_link, commit: commit_link)
  31. elsif @project.present?
  32. I18n.t('layout.messages.commits.header',
  33. committer: committer_link, commit: commit_link, project: @project.name)
  34. end.html_safe
  35. end
  36. 1 def image
  37. @image ||= if committer.is_a? User
  38. helpers.avatar_url(committer, :medium)
  39. elsif committer.is_a? Grit::Actor
  40. helpers.avatar_url_by_email(committer.email, :medium)
  41. else
  42. helpers.gravatar_url('Unknown', User::AVATAR_SIZES[:medium])
  43. end
  44. end
  45. 1 def date
  46. @date ||= @committed_date || @authored_date
  47. end
  48. 1 def expandable?
  49. true
  50. end
  51. 1 def buttons?
  52. false
  53. end
  54. 1 def content?
  55. content.present?
  56. end
  57. 1 def caption?
  58. true
  59. end
  60. 1 def comment_id?
  61. false
  62. end
  63. 1 def issue_referenced_state?
  64. false
  65. end
  66. 1 def reference_project
  67. @project if @is_reference_to_issue
  68. end
  69. 1 protected
  70. 1 def committer_link
  71. @committer_link ||= if committer.is_a? User
  72. link_to committer.uname, user_path(committer)
  73. elsif committer.is_a?(Grit::Actor) && committer.email.present?
  74. mail_to committer.email, committer.name
  75. else # unknown committer
  76. committer
  77. end
  78. end
  79. 1 def commit_link
  80. if @project
  81. link_to shortest_hash_id(@commit_hash), commit_path(@project, @commit_hash)
  82. else
  83. shortest_hash_id(@commit_hash)
  84. end
  85. end
  86. 1 def prepare_message
  87. (@caption, @content) = @commit_message.split("\n\n", 2)
  88. @caption = 'empty message' unless @caption.present?
  89. if @caption.length > 72
  90. tmp = '...' + @caption[69..-1]
  91. @content = (@content.present?) ? tmp + @content : tmp
  92. @caption = @caption[0..68] + '...'
  93. end
  94. end
  95. end

app/presenters/statistic_presenter.rb

42.86% lines covered

49 relevant lines. 21 lines covered and 28 lines missed.
    
  1. 1 class StatisticPresenter < ApplicationPresenter
  2. 1 attr_accessor :range_start, :range_end, :unit, :users_or_groups
  3. 1 def initialize(range_start: nil, range_end: nil, unit: nil, users_or_groups: nil)
  4. @range_start = range_start
  5. @range_end = range_end
  6. @unit = unit
  7. @users_or_groups = users_or_groups.to_s.split(/,/).map(&:strip).select(&:present?).first(3)
  8. end
  9. 1 def as_json(options = nil)
  10. {
  11. build_lists: {
  12. build_started: prepare_collection(build_lists_started),
  13. success: prepare_collection(build_lists_success),
  14. build_error: prepare_collection(build_lists_error),
  15. build_published: prepare_collection(build_lists_published),
  16. build_started_count: build_lists_started.sum(&:count),
  17. success_count: build_lists_success.sum(&:count),
  18. build_error_count: build_lists_error.sum(&:count),
  19. build_published_count: build_lists_published.sum(&:count),
  20. },
  21. commits: {
  22. chart: prepare_collection(commits_chart),
  23. commits_count: commits_chart.sum(&:count)
  24. },
  25. issues: {
  26. open: prepare_collection(issues_open),
  27. reopen: prepare_collection(issues_reopen),
  28. closed: prepare_collection(issues_closed),
  29. open_count: issues_open.sum(&:count),
  30. reopen_count: issues_reopen.sum(&:count),
  31. closed_count: issues_closed.sum(&:count)
  32. },
  33. pull_requests: {
  34. open: prepare_collection(pull_requests_open),
  35. merged: prepare_collection(pull_requests_merged),
  36. closed: prepare_collection(pull_requests_closed),
  37. open_count: pull_requests_open.sum(&:count),
  38. merged_count: pull_requests_merged.sum(&:count),
  39. closed_count: pull_requests_closed.sum(&:count)
  40. }
  41. }
  42. end
  43. 1 private
  44. 1 def user_ids
  45. @user_ids ||= User.where(uname: users_or_groups).pluck(:id)
  46. end
  47. 1 def group_ids
  48. @group_ids ||= Group.where(uname: users_or_groups).pluck(:id)
  49. end
  50. 1 def scope
  51. @scope ||= Statistic.for_period(range_start, range_end).
  52. for_users(user_ids).for_groups(group_ids).
  53. select("SUM(counter) as count, date_trunc('#{ unit }', activity_at) as activity_at").
  54. group("date_trunc('#{ unit }', activity_at)").order('activity_at')
  55. end
  56. 1 def issues_open
  57. @issues_open ||= scope.issues_open.to_a
  58. end
  59. 1 def issues_reopen
  60. @issues_reopen ||= scope.issues_reopen.to_a
  61. end
  62. 1 def issues_closed
  63. @issues_closed ||= scope.issues_closed.to_a
  64. end
  65. 1 def pull_requests_open
  66. @pull_requests_open ||= scope.pull_requests_open.to_a
  67. end
  68. 1 def pull_requests_merged
  69. @pull_requests_merged ||= scope.pull_requests_merged.to_a
  70. end
  71. 1 def pull_requests_closed
  72. @pull_requests_closed ||= scope.pull_requests_closed.to_a
  73. end
  74. 1 def commits_chart
  75. @commits_chart ||= scope.commits.to_a
  76. end
  77. 1 def build_lists_started
  78. @build_lists_started ||= scope.build_lists_started.to_a
  79. end
  80. 1 def build_lists_success
  81. @build_lists_success ||= scope.build_lists_success.to_a
  82. end
  83. 1 def build_lists_error
  84. @build_lists_error ||= scope.build_lists_error.to_a
  85. end
  86. 1 def build_lists_published
  87. @build_lists_published ||= scope.build_lists_published.to_a
  88. end
  89. 1 def prepare_collection(items)
  90. data = []
  91. to = range_start
  92. while to <= range_end
  93. from = to - 1.send(unit)
  94. y = items.find{ |i| i.activity_at > from && i.activity_at <= to }.try(:count)
  95. data << { x: to.strftime(format), y: y || 0 }
  96. to += 1.send(unit)
  97. end
  98. data
  99. end
  100. 1 def format
  101. @format ||= unit == :hour ? '%H:%M' : '%Y-%m-%d'
  102. end
  103. end

app/services/abf_worker_service/base.rb

29.55% lines covered

44 relevant lines. 13 lines covered and 31 lines missed.
    
  1. 1 module AbfWorkerService
  2. 1 class Base
  3. 1 REDIS_MAIN_KEY = 'abf-worker::build-lists-publish-task-manager::'
  4. %w(
  5. 1 PROJECTS_FOR_CLEANUP
  6. LOCKED_PROJECTS_FOR_CLEANUP
  7. LOCKED_BUILD_LISTS
  8. PACKAGES_FOR_CLEANUP
  9. REP_AND_PLS_OF_BUILD_LISTS_FOR_CLEANUP_FROM_TESTING
  10. BUILD_LISTS_FOR_CLEANUP_FROM_TESTING
  11. ).each do |kind|
  12. 6 const_set kind, "#{REDIS_MAIN_KEY}#{kind.downcase.gsub('_', '-')}"
  13. end
  14. 1 def self.cleanup_completed(projects_for_cleanup)
  15. projects_for_cleanup.each do |key|
  16. Redis.current.lrem LOCKED_PROJECTS_FOR_CLEANUP, 0, key
  17. Redis.current.hdel PACKAGES_FOR_CLEANUP, key
  18. end
  19. end
  20. 1 def self.cleanup_failed(projects_for_cleanup)
  21. projects_for_cleanup.each do |key|
  22. Redis.current.lrem LOCKED_PROJECTS_FOR_CLEANUP, 0, key
  23. Redis.current.lpush PROJECTS_FOR_CLEANUP, key
  24. end
  25. end
  26. 1 def self.cleanup_packages_from_testing(platform_id, repository_id, *build_lists)
  27. return if build_lists.blank?
  28. rep_pl = "#{repository_id}-#{platform_id}"
  29. key = "#{BUILD_LISTS_FOR_CLEANUP_FROM_TESTING}-#{rep_pl}"
  30. Redis.current.sadd REP_AND_PLS_OF_BUILD_LISTS_FOR_CLEANUP_FROM_TESTING, rep_pl
  31. Redis.current.sadd key, build_lists
  32. end
  33. 1 def self.unlock_build_list(build_list)
  34. Redis.current.lrem LOCKED_BUILD_LISTS, 0, build_list.id
  35. end
  36. 1 protected
  37. 1 def packages_structure
  38. structure = {sources: [], binaries: {}}
  39. Arch.pluck(:name).each{ |name| structure[:binaries][name.to_sym] = [] }
  40. structure
  41. end
  42. 1 def fill_packages(bl, results_map, field = :sha1)
  43. results_map[:sources] |= bl.packages.by_package_type('source').pluck(field).compact if field != :sha1
  44. binaries = bl.packages.by_package_type('binary').pluck(field).compact
  45. arch = bl.arch.name.to_sym
  46. results_map[:binaries][arch] |= binaries
  47. # Publish/remove i686 RHEL packages into/from x86_64
  48. if arch == :i586 && bl.build_for_platform.distrib_type == 'rhel' && bl.project.publish_i686_into_x86_64?
  49. results_map[:binaries][:x86_64] |= binaries
  50. end
  51. end
  52. 1 def filter_build_lists_without_packages(*build_lists)
  53. ids = []
  54. build_lists = build_lists.flatten.select do |build_list|
  55. sha1 = build_list.packages.pluck(:sha1).find do |sha1|
  56. !FileStoreService::File.new(sha1: sha1).exist?
  57. end
  58. if sha1.present?
  59. ids << build_list.id
  60. false
  61. else
  62. true
  63. end
  64. end
  65. BuildList.where(id: ids).update_all(status: BuildList::PACKAGES_FAIL)
  66. build_lists
  67. end
  68. end
  69. end

app/services/abf_worker_service/container.rb

42.86% lines covered

28 relevant lines. 12 lines covered and 16 lines missed.
    
  1. 1 module AbfWorkerService
  2. 1 class Container < Base
  3. 1 attr_accessor :build_list
  4. 1 def initialize(build_list)
  5. @build_list = build_list
  6. end
  7. 1 def create!
  8. cleanup_folder
  9. if filter_build_lists_without_packages(build_list).blank?
  10. build_list.fail_publish_container
  11. return
  12. end
  13. Resque.push(
  14. 'publish_worker', # Low priority
  15. 'class' => 'AbfWorker::PublishWorker',
  16. 'args' => [{
  17. id: build_list.id,
  18. cmd_params: cmd_params,
  19. main_script: 'build.sh',
  20. rollback_script: 'rollback.sh',
  21. platform: {
  22. platform_path: platform_path,
  23. type: distrib_type,
  24. name: build_list.build_for_platform.name,
  25. arch: build_list.arch.name
  26. },
  27. repository: {id: build_list.save_to_repository_id},
  28. time_living: 9600, # 160 min
  29. packages: packages,
  30. old_packages: packages_structure,
  31. build_list_ids: [build_list.id],
  32. projects_for_cleanup: [],
  33. extra: {create_container: true}
  34. }]
  35. )
  36. end
  37. 1 def destroy!
  38. system "rm -rf #{platform_path}"
  39. end
  40. 1 protected
  41. 1 def cmd_params
  42. {
  43. 'RELEASED' => false,
  44. 'REPOSITORY_NAME' => build_list.save_to_repository.name,
  45. 'TYPE' => distrib_type,
  46. 'IS_CONTAINER' => true,
  47. 'ID' => build_list.id,
  48. 'SAVE_TO_PLATFORM' => build_list.save_to_platform.name,
  49. 'BUILD_FOR_PLATFORM' => build_list.build_for_platform.name,
  50. 'FILE_STORE_ADDR' => APP_CONFIG['file_store_url']
  51. }.map{ |k, v| "#{k}=#{v}" }.join(' ')
  52. end
  53. 1 def cleanup_folder
  54. system "rm -rf #{platform_path} && mkdir -p #{platform_path}"
  55. end
  56. 1 def platform_path
  57. @platform_path ||= "#{build_list.save_to_platform.path}/container/#{build_list.id}"
  58. end
  59. 1 def distrib_type
  60. @distrib_type ||= build_list.build_for_platform.distrib_type
  61. end
  62. 1 def packages
  63. structure = packages_structure
  64. structure[:sources] = build_list.packages.by_package_type('source').pluck(:sha1).compact
  65. structure[:binaries][build_list.arch.name.to_sym] = build_list.packages.by_package_type('binary').pluck(:sha1).compact
  66. structure
  67. end
  68. end
  69. end

app/services/abf_worker_service/platform_metadata.rb

38.1% lines covered

21 relevant lines. 8 lines covered and 13 lines missed.
    
  1. 1 module AbfWorkerService
  2. 1 class PlatformMetadata < Base
  3. 1 attr_accessor :platform
  4. 1 def initialize(platform)
  5. @platform = platform
  6. end
  7. 1 def regenerate!
  8. return unless can_regenerate?
  9. Resque.push(
  10. 'publish_worker_default',
  11. 'class' => 'AbfWorker::PublishWorkerDefault',
  12. 'args' => [{
  13. id: Time.now.to_i,
  14. cmd_params: cmd_params,
  15. main_script: 'regenerate_platform_metadata.sh',
  16. platform: {
  17. platform_path: "#{platform.path}/repository",
  18. type: platform.distrib_type,
  19. name: platform.name,
  20. arch: 'x86_64'
  21. },
  22. time_living: 9600, # 160 min
  23. extra: {platform_id: platform.id, regenerate_platform: true}
  24. }]
  25. ) if platform.start_regeneration
  26. end
  27. 1 protected
  28. 1 def can_regenerate?
  29. repos = platform.repositories
  30. return false if repos.find{ |r| r.repo_lock_file_exists? }
  31. statuses = RepositoryStatus.where(platform_id: platform.id)
  32. return true if statuses.blank?
  33. statuses = statuses.map do |s|
  34. s.ready? || s.can_start_regeneration? || s.can_start_resign?
  35. end.uniq
  36. statuses == [true]
  37. end
  38. 1 def cmd_params
  39. {
  40. 'RELEASED' => platform.released,
  41. 'REPOSITORY_NAMES' => platform.repositories.map(&:name).join(','),
  42. 'TYPE' => platform.distrib_type,
  43. 'REGENERATE_PLATFORM_METADATA' => true,
  44. 'SAVE_TO_PLATFORM' => platform.name,
  45. 'BUILD_FOR_PLATFORM' => platform.name,
  46. 'FILE_STORE_ADDR' => APP_CONFIG['file_store_url']
  47. }.map{ |k, v| "#{k}=#{v}" }.join(' ')
  48. end
  49. end
  50. end

app/services/abf_worker_service/repository.rb

25.0% lines covered

40 relevant lines. 10 lines covered and 30 lines missed.
    
  1. 1 module AbfWorkerService
  2. 1 class Repository < Base
  3. 1 attr_accessor :repository
  4. 1 def initialize(repository)
  5. @repository = repository
  6. end
  7. 1 def destroy_project!(project)
  8. if repository.platform.personal?
  9. Platform.main.each do |main_platform|
  10. key = "#{project.id}-#{repository.id}-#{main_platform.id}"
  11. Redis.current.lpush PROJECTS_FOR_CLEANUP, key
  12. gather_old_packages project.id, repository.id, main_platform.id
  13. Redis.current.lpush PROJECTS_FOR_CLEANUP, ('testing-' << key)
  14. gather_old_packages project.id, repository.id, main_platform.id, true
  15. end
  16. else
  17. key = "#{project.id}-#{repository.id}-#{repository.platform_id}"
  18. Redis.current.lpush PROJECTS_FOR_CLEANUP, key
  19. gather_old_packages project.id, repository.id, repository.platform_id
  20. Redis.current.lpush PROJECTS_FOR_CLEANUP, ('testing-' << key)
  21. gather_old_packages project.id, repository.id, repository.platform_id, true
  22. end
  23. end
  24. 1 def resign!(repository_status)
  25. return if repository.repo_lock_file_exists?
  26. Resque.push(
  27. 'publish_worker_default',
  28. 'class' => "AbfWorker::PublishWorkerDefault",
  29. 'args' => [{
  30. id: repository.id,
  31. cmd_params: cmd_params,
  32. main_script: 'resign.sh',
  33. platform: {
  34. platform_path: "#{repository.platform.path}/repository",
  35. type: distrib_type,
  36. name: repository.platform.name,
  37. arch: 'x86_64'
  38. },
  39. repository: {id: repository.id},
  40. skip_feedback: true,
  41. time_living: 9600, # 160 min
  42. extra: {repository_status_id: repository_status.id, resign: true}
  43. }]
  44. ) if repository_status.start_resign
  45. end
  46. 1 protected
  47. 1 def cmd_params
  48. {
  49. 'RELEASED' => repository.platform.released,
  50. 'REPOSITORY_NAME' => repository.name,
  51. 'TYPE' => distrib_type,
  52. 'FILE_STORE_ADDR' => APP_CONFIG['file_store_url']
  53. }.map{ |k, v| "#{k}=#{v}" }.join(' ')
  54. end
  55. 1 def distrib_type
  56. @distrib_type ||= repository.platform.distrib_type
  57. end
  58. 1 def gather_old_packages(project_id, repository_id, platform_id, testing = false)
  59. build_lists_for_cleanup = []
  60. status = testing ? BuildList::BUILD_PUBLISHED_INTO_TESTING : BuildList::BUILD_PUBLISHED
  61. Arch.pluck(:id).each do |arch_id|
  62. bl = BuildList.where(project_id: project_id).
  63. where(new_core: true, status: status).
  64. where(save_to_repository_id: repository_id).
  65. where(build_for_platform_id: platform_id).
  66. where(arch_id: arch_id).
  67. order(:updated_at).first
  68. build_lists_for_cleanup << bl if bl
  69. end
  70. old_packages = packages_structure
  71. build_lists_for_cleanup.each do |bl|
  72. bl.last_published(testing).includes(:packages).limit(2).each do |old_bl|
  73. fill_packages(old_bl, old_packages, :fullname)
  74. end
  75. end
  76. key = (testing ? 'testing-' : '') << "#{project_id}-#{repository_id}-#{platform_id}"
  77. Redis.current.hset PACKAGES_FOR_CLEANUP, key, old_packages.to_json
  78. end
  79. end
  80. end

app/services/abf_worker_service/repository_metadata.rb

40.0% lines covered

20 relevant lines. 8 lines covered and 12 lines missed.
    
  1. 1 module AbfWorkerService
  2. 1 class RepositoryMetadata < Base
  3. 1 attr_accessor :repository, :repository_status
  4. 1 def initialize(repository_status)
  5. @repository_status = repository_status
  6. @repository = repository_status.repository
  7. end
  8. 1 def regenerate!
  9. # Checks mirror sync status
  10. return if repository.repo_lock_file_exists?
  11. platform_path = "#{repository.platform.path}/repository"
  12. if repository.platform.personal?
  13. platform_path << '/' << build_for_platform.name
  14. system "mkdir -p #{platform_path}"
  15. end
  16. Resque.push(
  17. 'publish_worker_default',
  18. 'class' => 'AbfWorker::PublishWorkerDefault',
  19. 'args' => [{
  20. id: Time.now.to_i,
  21. cmd_params: cmd_params,
  22. resign_rpms: @repository_status.resign_rpms,
  23. main_script: 'build.sh',
  24. rollback_script: 'rollback.sh',
  25. platform: {
  26. platform_path: platform_path,
  27. type: build_for_platform.distrib_type,
  28. name: build_for_platform.name,
  29. arch: 'x86_64'
  30. },
  31. repository: {id: repository.id},
  32. # time_living: 9600, # 160 min
  33. time_living: 14400, # 240 min
  34. extra: {repository_status_id: repository_status.id, regenerate: true}
  35. }]
  36. ) if repository_status.start_regeneration
  37. end
  38. 1 protected
  39. 1 def build_for_platform
  40. @build_for_platform ||= repository_status.platform
  41. end
  42. 1 def cmd_params
  43. {
  44. 'RELEASED' => repository.platform.released,
  45. 'REPOSITORY_NAME' => repository.name,
  46. 'TYPE' => build_for_platform.distrib_type,
  47. 'REGENERATE_METADATA' => true,
  48. 'SAVE_TO_PLATFORM' => repository.platform.name,
  49. 'BUILD_FOR_PLATFORM' => build_for_platform.name,
  50. 'FILE_STORE_ADDR' => APP_CONFIG['file_store_url']
  51. }.map{ |k, v| "#{k}=#{v}" }.join(' ')
  52. end
  53. end
  54. end

app/services/abf_worker_service/rpm.rb

18.49% lines covered

119 relevant lines. 22 lines covered and 97 lines missed.
    
  1. 1 module AbfWorkerService
  2. 1 class Rpm < Base
  3. 1 WORKERS_COUNT = APP_CONFIG['abf_worker']['publish_workers_count']
  4. 1 attr_accessor :save_to_repository_id, :build_for_platform_id, :testing
  5. 1 def initialize(save_to_repository_id, build_for_platform_id, testing)
  6. @save_to_repository_id = save_to_repository_id
  7. @build_for_platform_id = build_for_platform_id
  8. @testing = testing
  9. end
  10. 1 def self.publish!
  11. build_rpms
  12. build_rpms(true)
  13. end
  14. 1 def self.build_rpms(testing = false)
  15. available_repos = BuildList.
  16. select('MIN(updated_at) as min_updated_at, save_to_repository_id, build_for_platform_id').
  17. where(new_core: true, status: (testing ? BuildList::BUILD_PUBLISH_INTO_TESTING : BuildList::BUILD_PUBLISH)).
  18. group(:save_to_repository_id, :build_for_platform_id).
  19. order('min_updated_at ASC').
  20. limit(WORKERS_COUNT * 2) # because some repos may be locked
  21. locked_rep = RepositoryStatus.not_ready.joins(:platform).
  22. where(platforms: {platform_type: 'main'}).pluck(:repository_id)
  23. available_repos = available_repos.where('save_to_repository_id NOT IN (?)', locked_rep) unless locked_rep.empty?
  24. for_cleanup = Redis.current.lrange(PROJECTS_FOR_CLEANUP, 0, -1).map do |key|
  25. next if testing && key !~ /^testing-/
  26. rep, pl = *key.split('-').last(2)
  27. locked_rep.present? && locked_rep.include?(rep.to_i) ? nil : [rep.to_i, pl.to_i]
  28. end.compact
  29. for_cleanup_from_testing = Redis.current.smembers(REP_AND_PLS_OF_BUILD_LISTS_FOR_CLEANUP_FROM_TESTING).map do |key|
  30. next if Redis.current.scard("#{BUILD_LISTS_FOR_CLEANUP_FROM_TESTING}-#{key}") == 0
  31. rep, pl = *key.split('-')
  32. locked_rep.present? && locked_rep.include?(rep.to_i) ? nil : [rep.to_i, pl.to_i]
  33. end.compact if testing
  34. for_cleanup_from_testing ||= []
  35. counter = 1
  36. available_repos = available_repos.map{ |bl| [bl.save_to_repository_id, bl.build_for_platform_id] } | for_cleanup | for_cleanup_from_testing
  37. available_repos.each do |save_to_repository_id, build_for_platform_id|
  38. next if RepositoryStatus.not_ready.where(repository_id: save_to_repository_id, platform_id: build_for_platform_id).exists?
  39. break if counter > WORKERS_COUNT
  40. service = AbfWorkerService::Rpm.new(
  41. save_to_repository_id,
  42. build_for_platform_id,
  43. testing
  44. )
  45. counter += 1 if service.create
  46. end
  47. end
  48. 1 def create
  49. key = "#{save_to_repository_id}-#{build_for_platform_id}"
  50. projects_for_cleanup = Redis.current.lrange(PROJECTS_FOR_CLEANUP, 0, -1).select do |k|
  51. (testing && k =~ /^testing-[\d]+-#{key}$/) || (!testing && k =~ /^[\d]+-#{key}$/)
  52. end
  53. prepare_build_lists(projects_for_cleanup)
  54. projects_for_cleanup.each do |key|
  55. Redis.current.lrem PROJECTS_FOR_CLEANUP, 0, key
  56. packages = Redis.current.hget PACKAGES_FOR_CLEANUP, key
  57. next unless packages
  58. packages = JSON.parse packages
  59. old_packages[:sources] |= packages['sources']
  60. Arch.pluck(:name).each do |arch|
  61. old_packages[:binaries][arch.to_sym] |= packages['binaries'][arch] || []
  62. end
  63. end
  64. if testing
  65. build_lists_for_cleanup_from_testing = Redis.current.smembers("#{BUILD_LISTS_FOR_CLEANUP_FROM_TESTING}-#{save_to_repository_id}-#{build_for_platform_id}")
  66. BuildList.where(id: build_lists_for_cleanup_from_testing).each do |b|
  67. fill_packages(b, old_packages, :fullname)
  68. end if build_lists_for_cleanup_from_testing.present?
  69. end
  70. build_lists_for_cleanup_from_testing ||= []
  71. bl = build_lists[0]
  72. return false if !bl && old_packages[:sources].empty? && old_packages[:binaries].values.flatten.empty?
  73. # Checks mirror sync status
  74. return false if save_to_repository.repo_lock_file_exists? || !save_to_repository.platform.ready?
  75. repository_status = save_to_repository.repository_statuses.find_or_create_by(platform_id: build_for_platform_id)
  76. return false unless repository_status.publish
  77. options = {
  78. id: (bl ? bl.id : Time.now.to_i),
  79. cmd_params: cmd_params,
  80. main_script: 'build.sh',
  81. rollback_script: 'rollback.sh',
  82. platform: {
  83. platform_path: platform_path,
  84. type: distrib_type,
  85. name: build_for_platform.name,
  86. arch: (bl ? bl.arch.name : 'x86_64')
  87. },
  88. repository: {id: save_to_repository_id},
  89. time_living: 9600, # 160 min
  90. extra: {
  91. repository_status_id: repository_status.id,
  92. build_lists_for_cleanup_from_testing: build_lists_for_cleanup_from_testing
  93. }
  94. }
  95. packages, build_list_ids, new_sources = fill_in_packages
  96. push(options.merge({
  97. packages: packages,
  98. old_packages: old_packages,
  99. build_list_ids: build_list_ids,
  100. projects_for_cleanup: projects_for_cleanup
  101. }))
  102. lock_projects(projects_for_cleanup)
  103. cleanup(build_lists_for_cleanup_from_testing)
  104. return true
  105. end
  106. 1 protected
  107. 1 def platform_path
  108. @platform_path ||= begin
  109. path = "#{save_to_platform.path}/repository"
  110. if save_to_platform.personal?
  111. path << '/' << build_for_platform.name
  112. system "mkdir -p #{path}"
  113. end
  114. path
  115. end
  116. end
  117. 1 def cmd_params
  118. {
  119. 'RELEASED' => save_to_platform.released,
  120. 'REPOSITORY_NAME' => save_to_repository.name,
  121. 'TYPE' => distrib_type,
  122. 'SAVE_TO_PLATFORM' => save_to_platform.name,
  123. 'BUILD_FOR_PLATFORM' => build_for_platform.name,
  124. 'TESTING' => testing,
  125. 'FILE_STORE_ADDR' => APP_CONFIG['file_store_url']
  126. }.map{ |k, v| "#{k}=#{v}" }.join(' ')
  127. end
  128. 1 def save_to_repository
  129. @save_to_repository ||= ::Repository.find(save_to_repository_id)
  130. end
  131. 1 def save_to_platform
  132. @save_to_platform ||= save_to_repository.platform
  133. end
  134. 1 def build_for_platform
  135. @build_for_platform ||= Platform.find(build_for_platform_id)
  136. end
  137. 1 def distrib_type
  138. @distrib_type ||= build_for_platform.distrib_type
  139. end
  140. 1 def old_packages
  141. @old_packages ||= packages_structure
  142. end
  143. 1 def fill_in_packages
  144. packages, build_list_ids, new_sources = packages_structure, [], {}
  145. build_lists.each do |bl|
  146. # remove duplicates of sources for different arches
  147. bl.packages.by_package_type('source').each{ |s| new_sources["#{s.fullname}"] = s.sha1 }
  148. fill_packages(bl, packages)
  149. bl.last_published(testing).includes(:packages).limit(2).each{ |old_bl|
  150. fill_packages(old_bl, old_packages, :fullname)
  151. }
  152. # TODO: do more flexible
  153. # Removes old packages which already in the main repo
  154. bl.last_published(false).includes(:packages).limit(3).each{ |old_bl|
  155. fill_packages(old_bl, old_packages, :fullname)
  156. } if testing
  157. build_list_ids << bl.id
  158. Redis.current.lpush(LOCKED_BUILD_LISTS, bl.id)
  159. end
  160. packages[:sources] = new_sources.values.compact
  161. [packages, build_list_ids, new_sources]
  162. end
  163. 1 def lock_projects(projects_for_cleanup)
  164. projects_for_cleanup.each do |key|
  165. Redis.current.lpush LOCKED_PROJECTS_FOR_CLEANUP, key
  166. end
  167. end
  168. 1 def cleanup(build_lists_for_cleanup_from_testing)
  169. rep_pl = "#{save_to_repository_id}-#{build_for_platform_id}"
  170. r_key = "#{BUILD_LISTS_FOR_CLEANUP_FROM_TESTING}-#{rep_pl}"
  171. build_lists_for_cleanup_from_testing.each do |key|
  172. Redis.current.srem r_key, key
  173. end
  174. if Redis.current.scard(r_key) == 0
  175. Redis.current.srem REP_AND_PLS_OF_BUILD_LISTS_FOR_CLEANUP_FROM_TESTING, rep_pl
  176. end
  177. end
  178. 1 def push(options)
  179. Resque.push(
  180. 'publish_worker_default',
  181. 'class' => 'AbfWorker::PublishWorkerDefault',
  182. 'args' => [options]
  183. )
  184. end
  185. 1 def prepare_build_lists(projects_for_cleanup)
  186. # We should not to publish new builds into repository
  187. # if project of builds has been removed from repository.
  188. BuildList.where(
  189. project_id: projects_for_cleanup.map{ |k| k.split('-')[testing ? 1 : 0] }.uniq,
  190. save_to_repository_id: save_to_repository_id,
  191. status: [BuildList::BUILD_PUBLISH, BuildList::BUILD_PUBLISH_INTO_TESTING]
  192. ).update_all(status: BuildList::FAILED_PUBLISH)
  193. end
  194. 1 def build_lists
  195. @build_lists ||= begin
  196. build_lists = BuildList.
  197. where(new_core: true, status: (testing ? BuildList::BUILD_PUBLISH_INTO_TESTING : BuildList::BUILD_PUBLISH)).
  198. where(save_to_repository_id: save_to_repository_id).
  199. where(build_for_platform_id: build_for_platform_id).
  200. order(:updated_at)
  201. locked_ids = Redis.current.lrange(LOCKED_BUILD_LISTS, 0, -1)
  202. build_lists = build_lists.where('build_lists.id NOT IN (?)', locked_ids) if locked_ids.present?
  203. build_lists = build_lists.limit(1500)
  204. filter_build_lists_without_packages(build_lists.to_a)
  205. end
  206. end
  207. end
  208. end

app/services/file_store_service.rb

28.57% lines covered

35 relevant lines. 10 lines covered and 25 lines missed.
    
  1. 1 module FileStoreService
  2. 1 class File
  3. 1 URL = APP_CONFIG['file_store_url']
  4. 1 attr_accessor :sha1, :data
  5. # @param [String] sha1
  6. # @param [Hash] data:
  7. # - [String] path - path to file
  8. # - [String] fullname - file name
  9. 1 def initialize(sha1: nil, data: {})
  10. @sha1, @data = sha1, data
  11. end
  12. 1 def exist?
  13. resp = JSON(RestClient.get "#{URL}/api/v1/file_stores.json", params: {hash: sha1})
  14. if resp[0].respond_to?('[]') && resp[0]['file_name'] && resp[0]['sha1_hash']
  15. true
  16. else
  17. false
  18. end
  19. rescue # Dont care about it
  20. return false
  21. end
  22. 1 def save
  23. sha1 = Digest::SHA1.hexdigest(::File.read(data[:path]))
  24. return sha1 if exist?
  25. resource = RestClient::Resource.new("#{URL}/api/v1/upload", user: token)
  26. file = ::File.new(data[:path])
  27. # Hook for RestClient
  28. # See: [RestClient::Payload#create_file_field](https://github.com/rest-client/rest-client/blob/master/lib/restclient/payload.rb#L202-L215)
  29. fullname = data[:fullname]
  30. file.define_singleton_method(:original_filename) { fullname }
  31. resp = resource.post(file_store: { file: file })
  32. resp = JSON(resp)
  33. if resp.respond_to?(:[]) && resp['sha1_hash'].present?
  34. resp['sha1_hash']
  35. else
  36. nil
  37. end
  38. rescue RestClient::UnprocessableEntity => e # 422, file already exist
  39. return sha1
  40. rescue # Dont care about it
  41. return nil
  42. end
  43. 1 def destroy
  44. uri = URI(URL)
  45. Net::HTTP.start(uri.host, uri.port) do |http|
  46. req = Net::HTTP::Delete.new("/api/v1/file_stores/#{sha1}.json")
  47. req.basic_auth token, ''
  48. http.request(req)
  49. end
  50. rescue # Dont care about it
  51. end
  52. 1 protected
  53. 1 def token
  54. Rails.cache.fetch([FileStoreService::File, :token], expires_in: 10.minutes) do
  55. User.find_by(uname: 'file_store').authentication_token
  56. end
  57. end
  58. end
  59. end

lib/ext/bootstrap_link_renderer.rb

100.0% lines covered

0 relevant lines. 0 lines covered and 0 lines missed.
    
  1. # # See: https://github.com/bootstrap-ruby/will_paginate-bootstrap/blob/master/lib/bootstrap_pagination/bootstrap_renderer.rb
  2. # class BootstrapLinkRenderer < WillPaginate::ActionView::LinkRenderer
  3. # ELLIPSIS = "&hellip;"
  4. # def to_html
  5. # list_items = pagination.map do |item|
  6. # case item
  7. # when Fixnum
  8. # page_number(item)
  9. # else
  10. # send(item)
  11. # end
  12. # end.join(@options[:link_separator])
  13. # tag("ul", list_items, class: ul_class)
  14. # end
  15. # def container_attributes
  16. # super.except(*[:link_options])
  17. # end
  18. # protected
  19. # def page_number(page)
  20. # link_options = @options[:link_options] || {}
  21. # if page == current_page
  22. # tag("li", tag("span", page), class: "active")
  23. # else
  24. # tag("li", link(page, page, link_options.merge(rel: rel_value(page))))
  25. # end
  26. # end
  27. # def previous_or_next_page(page, text, classname)
  28. # link_options = @options[:link_options] || {}
  29. # if page
  30. # tag("li", link(text, page, link_options), class: classname)
  31. # else
  32. # tag("li", tag("span", text), class: "%s disabled" % classname)
  33. # end
  34. # end
  35. # def gap
  36. # tag("li", tag("span", ELLIPSIS), class: "disabled")
  37. # end
  38. # def previous_page
  39. # num = @collection.current_page > 1 && @collection.current_page - 1
  40. # previous_or_next_page(num, @options[:previous_label], "prev")
  41. # end
  42. # def next_page
  43. # num = @collection.current_page < @collection.total_pages && @collection.current_page + 1
  44. # previous_or_next_page(num, @options[:next_label], "next")
  45. # end
  46. # def ul_class
  47. # ["pagination", @options[:class]].compact.join(" ")
  48. # end
  49. # end

lib/ext/core/object.rb

40.0% lines covered

5 relevant lines. 2 lines covered and 3 lines missed.
    
  1. 1 class Object
  2. 1 def with_skip
  3. begin
  4. Thread.current[:skip] = true
  5. yield
  6. ensure
  7. Thread.current[:skip] = false
  8. end
  9. end
  10. end

lib/ext/core/string.rb

34.78% lines covered

23 relevant lines. 8 lines covered and 15 lines missed.
    
  1. 1 require 'charlock_holmes/string'
  2. 1 class String
  3. 1 def default_encoding!
  4. 117 default_encoding = Encoding.default_internal || Encoding::UTF_8
  5. 117 if ascii_only? # no need to encode if ascii
  6. 117 force_encoding(default_encoding)
  7. else # should encode
  8. options = {invalid: :replace, undef: :replace, replace: ''}
  9. if encoding.name == 'UTF-8'
  10. encode!(default_encoding, 'UTF-8', options)
  11. elsif (detected = detect_encoding) && detected[:encoding]
  12. force_encoding(detected[:encoding]).encode!(default_encoding, detected[:encoding], options)
  13. end
  14. scrub('')
  15. raise unless valid_encoding? # check result
  16. end
  17. 117 self
  18. rescue
  19. replace "--broken encoding: #{detect_encoding[:encoding] || 'unknown'}"
  20. # ensure
  21. # return self
  22. end
  23. # same as reverse.truncate.reverse
  24. 1 def rtruncate(length, options = {})
  25. chars = self.dup.mb_chars
  26. return self if chars.length <= length
  27. options[:omission] ||= "..."
  28. options[:separator] ||= '/'
  29. start = chars.length - length + options[:omission].mb_chars.length
  30. stop = options[:separator] ? (chars.index(options[:separator].mb_chars, start) || start) : start
  31. "#{options[:omission]}#{chars[stop..-1]}".to_s
  32. end
  33. end

lib/ext/git/gollum.rb

21.05% lines covered

38 relevant lines. 8 lines covered and 30 lines missed.
    
  1. 1 module Gollum
  2. 1 class Wiki
  3. # Public: Applies a reverse diff for a given page. If only 1 SHA is given,
  4. # the reverse diff will be taken from its parent (^SHA...SHA). If two SHAs
  5. # are given, the reverse diff is taken from SHA1...SHA2.
  6. #
  7. # page - The Gollum::Page to delete.
  8. # sha1 - String SHA1 of the earlier parent if two SHAs are given,
  9. # or the child.
  10. # sha2 - Optional String SHA1 of the child.
  11. # commit - The commit Hash details:
  12. # :message - The String commit message.
  13. # :name - The String author full name.
  14. # :email - The String email address.
  15. # :parent - Optional Grit::Commit parent to this update.
  16. #
  17. # Returns a String SHA1 of the new commit, or nil if the reverse diff does
  18. # not apply.
  19. 1 def revert_page_with_committer(page, sha1, sha2 = nil, commit = {})
  20. if sha2.is_a?(Hash)
  21. commit = sha2
  22. sha2 = nil
  23. end
  24. multi_commit = false
  25. patch = full_reverse_diff_for(page, sha1, sha2)
  26. committer = if obj = commit[:committer]
  27. multi_commit = true
  28. obj
  29. else
  30. Committer.new(self, commit)
  31. end
  32. parent = committer.parents[0]
  33. committer.options[:tree] = @repo.git.apply_patch(parent.sha, patch)
  34. return false unless committer.options[:tree]
  35. committer.after_commit do |index, sha|
  36. @access.refresh
  37. files = []
  38. if page
  39. files << [page.path, page.name, page.format]
  40. else
  41. # Grit::Diff can't parse reverse diffs.... yet
  42. patch.each_line do |line|
  43. if line =~ %r{^diff --git b/.+? a/(.+)$}
  44. path = $1
  45. ext = ::File.extname(path)
  46. name = ::File.basename(path, ext)
  47. if format = ::Gollum::Page.format_for(ext)
  48. files << [path, name, format]
  49. end
  50. end
  51. end
  52. end
  53. files.each do |(path, name, format)|
  54. dir = ::File.dirname(path)
  55. dir = '' if dir == '.'
  56. index.update_working_dir(dir, name, format)
  57. end
  58. end
  59. multi_commit ? committer : committer.commit
  60. end
  61. 1 alias_method :revert_page_without_committer, :revert_page
  62. 1 alias_method :revert_page, :revert_page_with_committer
  63. 1 def revert_commit_with_committer(sha1, sha2 = nil, commit = {})
  64. revert_page_with_committer(nil, sha1, sha2, commit)
  65. end
  66. 1 alias_method :revert_commit_without_committer, :revert_commit
  67. 1 alias_method :revert_commit, :revert_commit_with_committer
  68. end
  69. end

lib/ext/git/grit.rb

39.66% lines covered

58 relevant lines. 23 lines covered and 35 lines missed.
    
  1. 1 module Grit
  2. 1 class Commit
  3. # Fix: NoMethodError: undefined method 'touch' for Grit::Commit
  4. # see: model Comment belongs_to :commentable
  5. 1 def touch
  6. true
  7. end
  8. end
  9. 1 class Submodule
  10. 1 def binary?
  11. false
  12. end
  13. end
  14. 1 class Blob
  15. 1 include Linguist::BlobHelper
  16. 1 MAX_VIEW_SIZE = 2.megabytes
  17. 1 MAX_DATA_SIZE = 50.megabytes
  18. 1 def data_with_limit
  19. !huge? ? data_without_limit : nil # 'Error: blob is too big'
  20. end
  21. 1 def data_without_limit
  22. data
  23. end
  24. 1 def large?
  25. size.to_i > MAX_VIEW_SIZE
  26. end
  27. 1 def huge?
  28. size.to_i > MAX_DATA_SIZE
  29. end
  30. 1 def render_as
  31. @render_as ||= case
  32. when large?; :binary
  33. when image?; :image
  34. when text?; :text
  35. else
  36. :binary
  37. end
  38. end
  39. 1 attr_accessor :raw_mime_type
  40. 1 def raw_mime_type
  41. return @raw_mime_type if @raw_mime_type.present?
  42. if mime_type == 'text/rpm-spec'
  43. @raw_mime_type = 'text/x-rpm-spec'
  44. else
  45. @raw_mime_type = Linguist::Language.detect(self).try(:lexer).try(:mimetypes).try(:first)
  46. @raw_mime_type ||= DEFAULT_MIME_TYPE
  47. @raw_mime_type.gsub!('application', 'text')
  48. @raw_mime_type
  49. end
  50. end
  51. end
  52. 1 class Repo
  53. 1 def branches_and_tags
  54. branches + tags # @branches_and_tags ||= # ???
  55. end
  56. 1 def diff(a, b, *paths)
  57. diff = self.git.native('diff', {}, "#{a}...#{b}", '--', *paths)
  58. if diff =~ /diff --git a/
  59. diff = diff.sub(/.*?(diff --git a)/m, '\1')
  60. else
  61. diff = ''
  62. end
  63. Diff.list_from_string(self, diff)
  64. end
  65. # The diff stats for the given treeish
  66. # git diff --numstat -M a...b
  67. #
  68. # +a+ is the base treeish
  69. # +b+ is the head treeish
  70. #
  71. # Returns Grit::DiffStat[]
  72. 1 def diff_stats(a,b)
  73. stats = []
  74. lines = self.git.native(:diff, {numstat: true}, "#{a}...#{b}").split("\n")
  75. while !lines.empty?
  76. files = []
  77. while lines.first =~ /^([-\d]+)\s+([-\d]+)\s+(.+)/
  78. additions, deletions, filename = lines.shift.gsub(' => ', '=>').split
  79. additions, deletions = additions.to_i, deletions.to_i
  80. stat = DiffStat.new filename, additions, deletions
  81. stats << stat
  82. end
  83. end
  84. stats
  85. end
  86. end
  87. end
  88. 1 Grit::Git.git_timeout = 60
  89. # Grit::Git.git_max_size = 5.megabytes
  90. # Grit.debug = true
  91. 1 GAP_REPO_PATH = '/tmp/gap_repo.git'
  92. 1 unless File.directory? GAP_REPO_PATH
  93. Grit::Repo.init_bare(GAP_REPO_PATH)
  94. # FileUtils.chmod "a-w", GAP_REPO_PATH
  95. end

lib/ext/paperclip.rb

66.67% lines covered

18 relevant lines. 12 lines covered and 6 lines missed.
    
  1. # Patch to use paperclip with nginx upload module
  2. 1 module Paperclip
  3. 1 class Attachment
  4. 1 class UploadedPath
  5. 1 attr_reader :original_filename, :content_type, :size, :path
  6. 1 def initialize(uploaded_file)
  7. @original_filename = uploaded_file["name"].downcase
  8. @content_type = uploaded_file["content_type"].to_s.strip
  9. @file_size = uploaded_file["size"].to_i
  10. @path = uploaded_file["path"]
  11. end
  12. # TODO remove failed files
  13. 1 def to_tempfile; self; end
  14. 1 def size; @file_size; end
  15. 1 def close; end
  16. 1 def closed?; true; end
  17. end
  18. 1 def assign_with_upload(uploaded_file)
  19. uploaded_file = UploadedPath.new(uploaded_file) if uploaded_file.is_a?(Hash)
  20. assign_without_upload(uploaded_file)
  21. end
  22. 1 alias_method :assign_without_upload, :assign
  23. 1 alias_method :assign, :assign_with_upload
  24. end
  25. end

lib/ext/posix_spawn.rb

80.95% lines covered

42 relevant lines. 34 lines covered and 8 lines missed.
    
  1. 1 require 'posix/spawn'
  2. 1 module POSIX
  3. 1 module Spawn
  4. 1 class Child
  5. 1 include POSIX::Spawn
  6. 1 private
  7. # Start a select loop writing any input on the child's stdin and reading
  8. # any output from the child's stdout or stderr.
  9. #
  10. # input - String input to write on stdin. May be nil.
  11. # stdin - The write side IO object for the child's stdin stream.
  12. # stdout - The read side IO object for the child's stdout stream.
  13. # stderr - The read side IO object for the child's stderr stream.
  14. # timeout - An optional Numeric specifying the total number of seconds
  15. # the read/write operations should occur for.
  16. #
  17. # Returns an [out, err] tuple where both elements are strings with all
  18. # data written to the stdout and stderr streams, respectively.
  19. # Raises TimeoutExceeded when all data has not been read / written within
  20. # the duration specified in the timeout argument.
  21. # Raises MaximumOutputExceeded when the total number of bytes output
  22. # exceeds the amount specified by the max argument.
  23. 1 def read_and_write(input, stdin, stdout, stderr, timeout=nil, max=nil)
  24. 12 max = nil if max && max <= 0
  25. 12 @out, @err = '', ''
  26. 12 offset = 0
  27. # force all string and IO encodings to BINARY under 1.9 for now
  28. #if @out.respond_to?(:force_encoding) and stdin.respond_to?(:set_encoding)
  29. # [stdin, stdout, stderr].each do |fd|
  30. # fd.set_encoding('BINARY', 'BINARY')
  31. # end
  32. # @out.force_encoding('BINARY')
  33. # @err.force_encoding('BINARY')
  34. # input = input.dup.force_encoding('BINARY') if input
  35. #end
  36. 12 timeout = nil if timeout && timeout <= 0.0
  37. 12 @runtime = 0.0
  38. 12 start = Time.now
  39. 12 readers = [stdout, stderr]
  40. writers =
  41. 12 if input
  42. [stdin]
  43. else
  44. 12 stdin.close
  45. 12 []
  46. end
  47. 12 slice_method = input.respond_to?(:byteslice) ? :byteslice : :slice
  48. 12 t = timeout
  49. 12 while readers.any? || writers.any?
  50. 24 ready = IO.select(readers, writers, readers + writers, t)
  51. 24 raise TimeoutExceeded if ready.nil?
  52. # write to stdin stream
  53. 24 ready[1].each do |fd|
  54. begin
  55. boom = nil
  56. size = fd.write_nonblock(input)
  57. input = input.send(slice_method, size..-1)
  58. rescue Errno::EPIPE => boom
  59. rescue Errno::EAGAIN, Errno::EINTR
  60. end
  61. if boom || input.bytesize == 0
  62. stdin.close
  63. writers.delete(stdin)
  64. end
  65. end
  66. # read from stdout and stderr streams
  67. 24 ready[0].each do |fd|
  68. 36 buf = (fd == stdout) ? @out : @err
  69. begin
  70. 36 buf << fd.readpartial(BUFSIZE)
  71. rescue Errno::EAGAIN, Errno::EINTR
  72. rescue EOFError
  73. 24 readers.delete(fd)
  74. 24 fd.close
  75. end
  76. end
  77. # keep tabs on the total amount of time we've spent here
  78. 24 @runtime = Time.now - start
  79. 24 if timeout
  80. 24 t = timeout - @runtime
  81. 24 raise TimeoutExceeded if t < 0.0
  82. end
  83. # maybe we've hit our max output
  84. 24 if max && ready[0].any? && (@out.size + @err.size) > max
  85. raise MaximumOutputExceeded
  86. end
  87. end
  88. 12 [@out.mb_chars.default_encoding!, @err.mb_chars.default_encoding!]
  89. end
  90. end
  91. end
  92. end

lib/ext/rails/render_errors_in_forms.rb

25.0% lines covered

4 relevant lines. 1 lines covered and 3 lines missed.
    
  1. 1 ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
  2. if html_tag =~ /<label/
  3. %|<div class="fieldWithErrors">#{html_tag} <span class="error">#{[instance.error_message].join(', ')}</span></div>|.html_safe
  4. else
  5. html_tag
  6. end
  7. end

lib/ext/rails/reserved_name_validator.rb

87.5% lines covered

8 relevant lines. 7 lines covered and 1 lines missed.
    
  1. 1 class ReservedNameValidator < ActiveModel::EachValidator
  2. RESERVED_NAMES = %w{
  3. 1 about account add admin administrator api autocomplete_group_uname
  4. app apps archive archives auth
  5. blog
  6. config connect contact create commit commits
  7. dashboard delete direct_messages download downloads
  8. edit email
  9. faq favorites feed feeds follow followers following
  10. help home
  11. invitations invite
  12. jobs
  13. login log-in log_in logout log-out log_out logs
  14. map maps
  15. new none
  16. oauth oauth_clients openid
  17. privacy
  18. register remove replies rss root
  19. save search sessions settings
  20. signup sign-up sign_up signin sign-in sign_in signout sign-out sign_out
  21. sitemap ssl subscribe
  22. teams terms test tour trends tree
  23. unfollow unsubscribe upload uploads url user
  24. widget widgets wiki
  25. xfn xmpp
  26. }
  27. 1 def reserved_names
  28. 12 @reserved_names ||= RESERVED_NAMES +
  29. 425 Rails.application.routes.routes.map{|r| r.path.spec.to_s.match(/^\/([\w-]+)/)[1] rescue nil}.uniq.compact # current routes
  30. end
  31. 1 def validate_each(record, attribute, value)
  32. 12 if reserved_names.include?(value.to_s.downcase)
  33. record.errors.add(attribute, :exclusion, options.merge(value: value))
  34. end
  35. end
  36. end

lib/ext/rosa/constraints.rb

57.14% lines covered

21 relevant lines. 12 lines covered and 9 lines missed.
    
  1. 1 module Rosa
  2. 1 module Constraints
  3. 1 class Owner
  4. 1 def initialize(class_name, bang = false)
  5. 4 @class_name = class_name
  6. 4 @finder = 'find_by_insensitive_uname'
  7. 4 @finder << '!' if bang
  8. end
  9. 1 def matches?(request)
  10. @class_name.send(@finder, request.params[:uname]).present?
  11. end
  12. end
  13. 1 class AdminAccess
  14. 1 def self.matches?(request)
  15. !!request.env['warden'].user.try(:admin?)
  16. end
  17. end
  18. 1 class Treeish
  19. 1 def self.matches?(request)
  20. if (params = request.path_parameters) && params[:treeish] # parse existing branch (tag) and path
  21. branch_or_tag = begin
  22. (p = Project.find_by_owner_and_name params[:name_with_owner]) &&
  23. p.repo.branches_and_tags.map(&:name).sort{|a,b| b.length <=> a.length}.detect{|b| params[:treeish].start_with?(b)} ||
  24. params[:treeish].split('/').first
  25. end
  26. if path = params[:treeish].sub(branch_or_tag, '')[1..-1] and path.present?
  27. params[:path] = File.join([path, params[:path]].compact)
  28. end
  29. params[:treeish] = branch_or_tag
  30. end
  31. true
  32. end
  33. end
  34. end
  35. end

lib/ext/wiki/blob_entry.rb

25.0% lines covered

8 relevant lines. 2 lines covered and 6 lines missed.
    
  1. 1 class Gollum::BlobEntry
  2. 1 def name
  3. @name ||= begin
  4. fname = ::File.basename(@path)
  5. fname = fname.gsub(/\\\d+/).each { |q| q[1..-1].to_i(8).chr }.force_encoding('utf-8')
  6. fname.gsub!(/^"/, '')
  7. fname.gsub!(/"$/, '')
  8. fname
  9. end
  10. end
  11. end

lib/plugins.rb

100.0% lines covered

3 relevant lines. 3 lines covered and 0 lines missed.
    
  1. 1 Dir[File.join(File.dirname(__FILE__), 'plugins', '*.rb')].each do |f|
  2. 4 $:.unshift File.dirname(f)
  3. 4 require f
  4. end

lib/plugins/grack.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. 1 module Grack
  2. 1 extend ActiveSupport::Autoload
  3. 1 autoload :Base
  4. 1 autoload :Auth
  5. 1 autoload :Handler
  6. end

lib/plugins/grack/auth.rb

45.45% lines covered

11 relevant lines. 5 lines covered and 6 lines missed.
    
  1. 1 module Grack
  2. 1 class Auth < Base
  3. 1 def initialize(app)
  4. 1 @app = app
  5. end
  6. # TODO tests!!!
  7. 1 def _call(env)
  8. super
  9. if git?
  10. return render_not_found if project.blank?
  11. return ::Rack::Auth::Basic.new(@app) do |u, p|
  12. user = User.auth_by_token_or_login_pass(u, p) and
  13. ability = ProjectPolicy.new(user, project).send("#{action}?") and
  14. ENV['GL_ID'] = "user-#{user.id}" and
  15. ENV['GL_REPO_NAME'] = project.path
  16. end.call(env) unless project.public? && read? # need auth
  17. end
  18. @app.call(env) # next app in stack
  19. end
  20. end
  21. end

lib/plugins/grack/base.rb

48.39% lines covered

31 relevant lines. 15 lines covered and 16 lines missed.
    
  1. 1 module Grack
  2. 1 class Base # abstract
  3. 1 def call(env)
  4. dup._call(env)
  5. end
  6. 1 protected
  7. 1 def _call(env)
  8. @env = env
  9. @project = nil
  10. end
  11. 1 def git?
  12. @env['HTTP_USER_AGENT'] =~ /^git\//
  13. end
  14. 1 def read?
  15. (get? && !(@env['REQUEST_URI'] =~ /git-receive-pack$/)) ||
  16. (post? && !(@env['REQUEST_URI'] =~ /git-upload-pack$/).nil?)
  17. end
  18. 1 def write?
  19. !read?
  20. end
  21. 1 def get?
  22. @env['REQUEST_METHOD'] == 'GET'
  23. end
  24. 1 def post?
  25. @env['REQUEST_METHOD'] == 'POST'
  26. end
  27. 1 def action
  28. write? ? :write : :read
  29. end
  30. 1 def project
  31. @project ||= begin
  32. uname, name = @env['PATH_INFO'].split('/')[1,2]
  33. name.gsub!(/(\.wiki)?\.git$/, '')
  34. Project.find_by_owner_and_name uname, name
  35. end
  36. end
  37. 1 PLAIN_TYPE = {"Content-Type" => "text/plain"}
  38. 1 def render_not_found
  39. [404, PLAIN_TYPE, ["Not Found"]]
  40. end
  41. 1 def render_no_access
  42. [403, PLAIN_TYPE, ["Forbidden"]]
  43. end
  44. end
  45. end
  46. # ({"HTTP_ACCEPT"=>"*/*", "HTTP_HOST"=>"localhost:3000", "SERVER_NAME"=>"localhost", "rack.url_scheme"=>"http", "PASSENGER_CONNECT_PASSWORD"=>"xbRC6murG5bIDTsaed8ksaZhjf8yFsadlX4QL0qWNbS", "HTTP_USER_AGENT"=>"git/1.7.7.2", "PASSENGER_SPAWN_METHOD"=>"smart-lv2", "PASSENGER_FRIENDLY_ERROR_PAGES"=>"true", "CONTENT_LENGTH"=>"0", "rack.errors"=>#<IO:0x108494a90>, "SERVER_PROTOCOL"=>"HTTP/1.1", "action_dispatch.secret_token"=>"df2fb72d477491cf15ef0f93449bcb59c3412c255c2386e07772935565c1b6ad23539ed804b8f12e3221e47abb78f5b679693c391acb33477be0e633e7a2e2a4", "rack.run_once"=>false, "rack.version"=>[1, 0], "REMOTE_ADDR"=>"127.0.0.1", "SERVER_SOFTWARE"=>"nginx/1.0.6", "PASSENGER_MIN_INSTANCES"=>"1", "PATH_INFO"=>"/codefoundry.git/info/refs", "SERVER_ADDR"=>"127.0.0.1", "SCRIPT_NAME"=>"", "action_dispatch.parameter_filter"=>[:password], "action_dispatch.show_exceptions"=>true, "rack.multithread"=>false, "PASSENGER_USER"=>"", "PASSENGER_ENVIRONMENT"=>"development", "PASSENGER_SHOW_VERSION_IN_HEADER"=>"true", "rack.multiprocess"=>true, "REMOTE_PORT"=>"49387", "REQUEST_URI"=>"/codefoundry.git/info/refs", "SERVER_PORT"=>"3000", "SCGI"=>"1", "PASSENGER_APP_TYPE"=>"rack", "PASSENGER_USE_GLOBAL_QUEUE"=>"true", "REQUEST_METHOD"=>"GET", "PASSENGER_GROUP"=>"", "PASSENGER_DEBUGGER"=>"false", "DOCUMENT_ROOT"=>"/Users/pasha/Sites/rosa-build/public", "_"=>"_", "PASSENGER_FRAMEWORK_SPAWNER_IDLE_TIME"=>"-1", "UNION_STATION_SUPPORT"=>"false", "rack.input"=>#<PhusionPassenger::Utils::RewindableInput:0x10bb55a20 @rewindable_io=nil, @io=#<PhusionPassenger::Utils::UnseekableSocket:0x10bb56c90 @socket=#<UNIXSocket:0x10bb56b28>>, @unlinked=false>, "HTTP_PRAGMA"=>"no-cache", "QUERY_STRING"=>"", "PASSENGER_APP_SPAWNER_IDLE_TIME"=>"-1"}) (process 41940, thread #<Thread:0x1084a1268>)
  47. # {"rack.session"=>{}, "HTTP_ACCEPT"=>"*/*", "HTTP_HOST"=>"localhost:3000", "SERVER_NAME"=>"localhost", "action_dispatch.remote_ip"=>#<ActionDispatch::RemoteIp::RemoteIpGetter:0x10b621338 @check_ip_spoofing=true, @env={...}, @trusted_proxies=/(^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\.)/i>, "rack.url_scheme"=>"http", "PASSENGER_CONNECT_PASSWORD"=>"dljpLA91qGH4v2gwaccoAxFysOmSkEFbRtPyPOe9953", "HTTP_USER_AGENT"=>"git/1.7.7.2", "PASSENGER_SPAWN_METHOD"=>"smart-lv2", "PASSENGER_FRIENDLY_ERROR_PAGES"=>"true", "CONTENT_LENGTH"=>"0", "action_dispatch.request.unsigned_session_cookie"=>{}, "rack.errors"=>#<IO:0x10724baa0>, "SERVER_PROTOCOL"=>"HTTP/1.1", "action_dispatch.secret_token"=>"df2fb72d477491cf15ef0f93449bcb59c3412c255c2386e07772935565c1b6ad23539ed804b8f12e3221e47abb78f5b679693c391acb33477be0e633e7a2e2a4", "rack.run_once"=>false, "rack.version"=>[1, 0], "REMOTE_ADDR"=>"127.0.0.1", "SERVER_SOFTWARE"=>"nginx/1.0.6", "PASSENGER_MIN_INSTANCES"=>"1", "PATH_INFO"=>"/pasha/mc.git/info/refs", "SERVER_ADDR"=>"127.0.0.1", "SCRIPT_NAME"=>"", "action_dispatch.parameter_filter"=>[:password], "action_dispatch.show_exceptions"=>true, "rack.multithread"=>false, "PASSENGER_USER"=>"", "PASSENGER_ENVIRONMENT"=>"development", "PASSENGER_SHOW_VERSION_IN_HEADER"=>"true", "action_dispatch.cookies"=>{}, "rack.multiprocess"=>true, "REMOTE_PORT"=>"49643", "REQUEST_URI"=>"/pasha/mc.git/info/refs", "SERVER_PORT"=>"3000", "SCGI"=>"1", "PASSENGER_APP_TYPE"=>"rack", "PASSENGER_USE_GLOBAL_QUEUE"=>"true", "rack.session.options"=>{:httponly=>true, :expire_after=>nil, :domain=>nil, :path=>"/", :secure=>false, :id=>nil}, "REQUEST_METHOD"=>"GET", "PASSENGER_GROUP"=>"", "PASSENGER_DEBUGGER"=>"false", "DOCUMENT_ROOT"=>"/Users/pasha/Sites/rosa-build/public", "warden"=>Warden::Proxy:2242130160 @config={:failure_app=>Devise::FailureApp, :default_scope=>:user, :intercept_401=>false, :scope_defaults=>{}, :default_strategies=>{:user=>[:rememberable, :database_authenticatable]}}, "_"=>"_", "PASSENGER_FRAMEWORK_SPAWNER_IDLE_TIME"=>"-1", "UNION_STATION_SUPPORT"=>"false", "rack.input"=>#<PhusionPassenger::Utils::RewindableInput:0x10b6225f8 @rewindable_io=nil, @io=#<PhusionPassenger::Utils::UnseekableSocket:0x10a8f5a10 @socket=#<UNIXSocket:0x10b623700>>, @unlinked=false>, "HTTP_PRAGMA"=>"no-cache", "QUERY_STRING"=>"", "PASSENGER_APP_SPAWNER_IDLE_TIME"=>"-1"}

lib/plugins/grack/handler.rb

60.0% lines covered

10 relevant lines. 6 lines covered and 4 lines missed.
    
  1. 1 module Grack
  2. 1 class Handler < Base
  3. 1 def initialize(app, config)
  4. 1 @app = app
  5. 1 @config = config
  6. end
  7. 1 def _call(env)
  8. super
  9. if git?
  10. Grack::App.new(@config).call(env)
  11. else
  12. @app.call(env)
  13. end
  14. end
  15. end
  16. end

lib/plugins/redcarpet.rb

100.0% lines covered

1 relevant lines. 1 lines covered and 0 lines missed.
    
  1. 1 require 'redcarpet/render/gitlab_html.rb'

lib/plugins/redcarpet/render/gitlab_html.rb

38.1% lines covered

21 relevant lines. 8 lines covered and 13 lines missed.
    
  1. 1 class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
  2. 1 attr_reader :template
  3. 1 alias_method :h, :template
  4. 1 def initialize(template, options = {})
  5. @template = template
  6. @project = @template.instance_variable_get("@project")
  7. @options = options.dup
  8. super options
  9. end
  10. 1 def block_code(code, language)
  11. # New lines are placed to fix an rendering issue
  12. # with code wrapped inside <h1> tag for next case:
  13. #
  14. # # Title kinda h1
  15. #
  16. # ruby code here
  17. #
  18. <<-HTML
  19. <div class="highlighted-data #{h.user_color_scheme_class}">
  20. <div class="highlight">
  21. <pre><code class="#{language}">#{h.send(:html_escape, code)}</code></pre>
  22. </div>
  23. </div>
  24. HTML
  25. end
  26. 1 def link(link, title, content)
  27. h.link_to_gfm(content, link, title: title)
  28. end
  29. 1 def header(text, level)
  30. if @options[:no_header_anchors]
  31. "<h#{level}>#{text}</h#{level}>"
  32. else
  33. id = ActionController::Base.helpers.strip_tags(h.gfm(text)).downcase() \
  34. .gsub(/[^a-z0-9_-]/, '-').gsub(/-+/, '-').gsub(/^-/, '').gsub(/-$/, '')
  35. "<h#{level} id=\"#{id}\">#{text}<a href=\"\##{id}\"></a></h#{level}>"
  36. end
  37. end
  38. 1 def postprocess(full_document)
  39. unless @template.instance_variable_get("@project_wiki") || @project.nil?
  40. full_document = h.create_relative_links(full_document)
  41. end
  42. h.gfm(full_document)
  43. end
  44. end

lib/plugins/rosa_presenter.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. 1 module RosaPresenter
  2. 1 extend ActiveSupport::Autoload
  3. 1 autoload :Activation
  4. 1 autoload :Base
  5. 1 VERSION = "0.0.1"
  6. end
  7. 1 ActionController::Base.send(:include, RosaPresenter::Activation)

lib/plugins/rosa_presenter/activation.rb

100.0% lines covered

7 relevant lines. 7 lines covered and 0 lines missed.
    
  1. # This code based on https://github.com/ihoka/viewtastic
  2. 1 module RosaPresenter
  3. 1 module Activation
  4. 1 def self.included(klass) # :nodoc:
  5. 1 klass.prepend_before_action :activate_rosa_presenter
  6. end
  7. 1 private
  8. 1 def activate_rosa_presenter
  9. 3 RosaPresenter::Base.controller = self
  10. end
  11. end
  12. end

lib/plugins/rosa_presenter/base.rb

60.61% lines covered

33 relevant lines. 20 lines covered and 13 lines missed.
    
  1. # This code based on https://github.com/ihoka/viewtastic
  2. 1 module RosaPresenter
  3. 1 class Base
  4. # include ActionDispatch::Routing::UrlFor
  5. 1 include ActionView::Helpers::UrlHelper
  6. 1 include ActionView::Helpers::TextHelper
  7. 1 include ActionView::Helpers::OutputSafetyHelper
  8. 1 include ActionView::Helpers::JavaScriptHelper
  9. 1 include Rails.application.routes.url_helpers
  10. 1 def initialize(item, opts)
  11. end
  12. 1 def controller
  13. Thread.current[:rosa_presenter_controller]
  14. end
  15. 1 def helpers
  16. controller.view_context
  17. end
  18. # TODO it needs to be refactored!
  19. 1 class << self
  20. 1 def present(item, opts, &block)
  21. block.call(self.new(item, opts))
  22. end
  23. 1 def present_collection(collection, &block)
  24. res = collection.map {|e| self.new(*e)}
  25. if block.present?
  26. res = res.inject('') do |akk, presenter|
  27. akk << block.call(presenter)
  28. akk
  29. end
  30. end
  31. return res
  32. end
  33. 1 def controller=(value) #:nodoc:
  34. 3 Thread.current[:rosa_presenter_controller] = value
  35. end
  36. 1 def controller #:nodoc:
  37. Thread.current[:rosa_presenter_controller]
  38. end
  39. 1 def activated? #:nodoc:
  40. !controller.nil?
  41. end
  42. end
  43. 1 protected
  44. 1 def t(*args)
  45. I18n.translate(*args)
  46. end
  47. 1 def l(*args)
  48. I18n.localize(*args)
  49. end
  50. end
  51. end

lib/plugins/rpm.rb

35.71% lines covered

28 relevant lines. 10 lines covered and 18 lines missed.
    
  1. 1 require 'ffi'
  2. 1 module RPM
  3. 1 def self.compareVREs(vre1, vre2)
  4. e1, v1, r1 = vre1
  5. e2, v2, r2 = vre2
  6. e1 = '0' if !e1.present?
  7. e2 = '0' if !e2.present?
  8. rc = compare_values(e1, e2)
  9. if rc == 0
  10. rc = compare_values(v1, v2)
  11. if rc == 0
  12. rc = compare_values(r1, r2)
  13. end
  14. end
  15. return rc
  16. end
  17. 1 class << self
  18. 1 private
  19. 1 def compare_values(val1, val2)
  20. if !val1.present? && !val2.present?
  21. return 0
  22. elsif val1.present? && !val2.present?
  23. return 1
  24. elsif !val1.present? && val2.present?
  25. return -1
  26. end
  27. return C.rpmvercmp(val1, val2)
  28. end
  29. end
  30. 1 module C
  31. 1 extend ::FFI::Library
  32. begin
  33. 1 ffi_lib ['librpm.so.9', 'rpm']
  34. rescue LoadError => e
  35. raise(
  36. "Can't find rpm libs on your system: #{e.message}"
  37. )
  38. end
  39. 1 attach_function 'rpmvercmp', [:string, :string], :int
  40. end
  41. end